summaryrefslogtreecommitdiff
path: root/exa
diff options
context:
space:
mode:
Diffstat (limited to 'exa')
-rw-r--r--exa/exa.c1252
-rw-r--r--exa/exa.h240
-rw-r--r--exa/exa_accel.c1252
-rw-r--r--exa/exa_migration.c1252
-rw-r--r--exa/exa_offscreen.c374
-rw-r--r--exa/exa_priv.h281
-rw-r--r--exa/exa_render.c572
-rw-r--r--exa/exa_unaccel.c365
8 files changed, 5588 insertions, 0 deletions
diff --git a/exa/exa.c b/exa/exa.c
new file mode 100644
index 000000000..c2d0db063
--- /dev/null
+++ b/exa/exa.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "exaPriv.h"
+#include "fontstruct.h"
+#include "dixfontstr.h"
+#include "xf86str.h"
+#include "xf86.h"
+#include "exa.h"
+
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#if DEBUG_MIGRATE
+#define DBG_MIGRATE(a) ErrorF a
+#else
+#define DBG_MIGRATE(a)
+#endif
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+#define STRACE
+#define TRACE
+
+int exaGeneration;
+int exaScreenPrivateIndex;
+int exaPixmapPrivateIndex;
+
+#define EXA_PIXMAP_SCORE_MOVE_IN 10
+#define EXA_PIXMAP_SCORE_MAX 20
+#define EXA_PIXMAP_SCORE_MOVE_OUT -10
+#define EXA_PIXMAP_SCORE_MIN -20
+#define EXA_PIXMAP_SCORE_PINNED 1000
+#define EXA_PIXMAP_SCORE_INIT 1001
+
+void
+exaDrawableDirty (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap)((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr)pDrawable;
+
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (pExaPixmap != NULL)
+ pExaPixmap->dirty = TRUE;
+}
+
+static void
+exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ PixmapPtr pPixmap = area->privData;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv(pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("Save 0x%08p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src_pitch = pPixmap->devKind;
+ dst_pitch = pExaPixmap->devKind;
+
+ src = pPixmap->devPrivate.ptr;
+ dst = pExaPixmap->devPrivate.ptr;
+
+ if (pExaScr->info->accel.DownloadFromScreen)
+ {
+ if (pExaScr->info->accel.DownloadFromScreen(pPixmap,
+ pPixmap->drawable.x,
+ pPixmap->drawable.y,
+ pPixmap->drawable.width,
+ pPixmap->drawable.height,
+ dst,
+ dst_pitch)) {
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+ return;
+ }
+ }
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+
+#if 0
+ if (!pExaPixmap->dirty)
+ return;
+#endif
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ i = pPixmap->drawable.height;
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+}
+
+static int
+exaLog2(int val)
+{
+ int bits;
+
+ if (!val)
+ return 0;
+ for (bits = 0; val != 0; bits++)
+ val >>= 1;
+ return bits - 1;
+}
+
+static Bool
+exaPixmapAllocArea (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int bpp = pPixmap->drawable.bitsPerPixel;
+ CARD16 h = pPixmap->drawable.height;
+ CARD16 w = pPixmap->drawable.width;
+ int pitch;
+
+ if (pExaScr->info->card.flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
+ w = 1 << (exaLog2(w - 1) + 1);
+ pitch = (w * bpp / 8 + pExaScr->info->card.offscreenPitch - 1) &
+ ~(pExaScr->info->card.offscreenPitch - 1);
+
+ pExaPixmap->devKind = pPixmap->devKind;
+ pExaPixmap->devPrivate = pPixmap->devPrivate;
+ pExaPixmap->area = exaOffscreenAlloc (pScreen, pitch * h,
+ pExaScr->info->card.offscreenByteAlign,
+ FALSE,
+ exaPixmapSave, (pointer) pPixmap);
+ if (!pExaPixmap->area)
+ return FALSE;
+
+ DBG_PIXMAP(("++ 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ pPixmap->devKind = pitch;
+
+ pPixmap->devPrivate.ptr = (pointer) ((CARD8 *) pExaScr->info->card.memoryBase + pExaPixmap->area->offset);
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ return TRUE;
+}
+
+void
+exaMoveInPixmap (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("-> 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src = pPixmap->devPrivate.ptr;
+ src_pitch = pPixmap->devKind;
+
+ if (!exaPixmapAllocArea (pPixmap))
+ return;
+
+ pExaPixmap->dirty = FALSE;
+
+ if (pExaScr->info->accel.UploadToScreen)
+ {
+ if (pExaScr->info->accel.UploadToScreen(pPixmap, src, src_pitch))
+ return;
+ }
+
+ dst = pPixmap->devPrivate.ptr;
+ dst_pitch = pPixmap->devKind;
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ i = pPixmap->drawable.height;
+ ErrorF("dst = %p, src = %p,(%d, %d) height = %d, mem_base = %p, offset = %d\n",
+ dst, src, dst_pitch, src_pitch,
+ i, pExaScr->info->card.memoryBase, ExaGetPixmapPriv(pPixmap)->area->offset);
+
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ ErrorF("done\n");
+}
+
+static void
+exaMoveOutPixmap (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+ ExaOffscreenArea *area = pExaPixmap->area;
+
+ DBG_MIGRATE (("<- 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ STRACE;
+ if (area)
+ {
+ exaPixmapSave (pPixmap->drawable.pScreen, area);
+ exaOffscreenFree (pPixmap->drawable.pScreen, area);
+ }
+}
+
+void
+exaPixmapUseScreen (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ STRACE;
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+ return;
+
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
+ exaMoveInPixmap(pPixmap);
+ pExaPixmap->score = 0;
+ }
+
+ if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
+ {
+ pExaPixmap->score++;
+ if (!exaPixmapIsOffscreen(pPixmap) &&
+ pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN)
+ exaMoveInPixmap (pPixmap);
+ }
+ ExaOffscreenMarkUsed (pPixmap);
+}
+
+void
+exaPixmapUseMemory (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ 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->area &&
+ pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT)
+ exaMoveOutPixmap (pPixmap);
+ }
+}
+
+static Bool
+exaDestroyPixmap (PixmapPtr pPixmap)
+{
+ if (pPixmap->refcnt == 1)
+ {
+ ExaPixmapPriv (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 = pExaPixmap->devPrivate;
+ pPixmap->devKind = pExaPixmap->devKind;
+ }
+ }
+ return fbDestroyPixmap (pPixmap);
+}
+
+static PixmapPtr
+exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+ int bpp;
+
+ bpp = BitsPerPixel (depth);
+ if (bpp == 32 && depth == 24)
+ {
+ int format;
+ ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
+ for (format = 0; format < MAXFORMATS && pScrn->formats[format].depth; ++format)
+ if (pScrn->formats[format].depth == 24)
+ {
+ bpp = pScrn->formats[format].bitsPerPixel;
+ break;
+ }
+ }
+
+ pPixmap = fbCreatePixmapBpp (pScreen, w, h, depth, bpp);
+ if (!pPixmap)
+ return NULL;
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (!w || !h)
+ pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+ else
+ pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+
+ pExaPixmap->area = NULL;
+ pExaPixmap->dirty = FALSE;
+
+ return pPixmap;
+}
+
+Bool
+exaPixmapIsOffscreen(PixmapPtr p)
+{
+ ScreenPtr pScreen = p->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
+ (CARD8 *) pExaScr->info->card.memoryBase) <
+ pExaScr->info->card.memorySize);
+}
+
+PixmapPtr
+exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
+{
+ PixmapPtr pPixmap;
+ int x, y;
+
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+#ifdef COMPOSITE
+ x = -pPixmap->screen_x;
+ y = -pPixmap->screen_y;
+#else
+ x = 0;
+ y = 0;
+#endif
+ }
+ else
+ {
+ pPixmap = (PixmapPtr) pDrawable;
+ x = 0;
+ y = 0;
+ }
+ *xp = x;
+ *yp = y;
+ if (exaPixmapIsOffscreen (pPixmap))
+ return pPixmap;
+ else
+ return NULL;
+}
+
+Bool
+exaDrawableIsOffscreen (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr) pDrawable;
+ return exaPixmapIsOffscreen (pPixmap);
+}
+
+#if 0
+static void
+exaFillTiled(int dst_x,
+ int dst_y,
+ int width,
+ int height,
+ int src_x,
+ int src_y,
+ int src_width,
+ int src_height,
+ void (*Copy) (int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height))
+{
+ modulus (src_x, src_width, src_x);
+ modulus (src_y, src_height, src_y);
+
+ while (height)
+ {
+ int dst_x_tmp = dst_x;
+ int src_x_tmp = src_x;
+ int width_tmp = width;
+ int height_left = src_height - src_y;
+ int height_this = min (height, height_left);
+
+ while (width_tmp)
+ {
+ int width_left = src_width - src_x_tmp;
+ int width_this = min (width_tmp, width_left);
+
+ (*Copy) (src_x_tmp, src_y,
+ dst_x_tmp, dst_y,
+ width_this, height_this);
+
+ width_tmp -= width_this;
+ dst_x_tmp += width_this;
+ }
+ height -= height_this;
+ dst_y += height_this;
+ src_y = 0;
+ }
+}
+#endif
+
+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;
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (n--)
+ {
+ fullX1 = ppt->x;
+ fullY1 = ppt->y;
+ fullX2 = fullX1 + (int) *pwidth;
+ ppt++;
+ pwidth++;
+
+ if (fullY1 < extentY1 || extentY2 <= fullY1)
+ continue;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullX1 >= fullX2)
+ continue;
+
+ nbox = REGION_NUM_RECTS (pClip);
+ if (nbox == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + off_x, fullY1 + off_y,
+ fullX2 + off_x, fullY1 + 1 + off_y);
+ }
+ else
+ {
+ pbox = REGION_RECTS(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->accel.Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ pbox++;
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pScreen);
+}
+
+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);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ STRACE;
+
+ /* Migrate pixmaps to same place as destination */
+ if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
+ if (exaDrawableIsOffscreen (pDstDrawable))
+ exaPixmapUseScreen ((PixmapPtr) pSrcDrawable);
+ else
+ exaPixmapUseMemory ((PixmapPtr) pSrcDrawable);
+ }
+
+ if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
+ (pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
+ (*pExaScr->info->accel.PrepareCopy) (pSrcPixmap,
+ pDstPixmap,
+ dx,
+ dy,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES))
+ {
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.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->accel.DoneCopy) (pDstPixmap);
+ exaMarkSync(pDstDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDstDrawable->pScreen);
+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
+ pbox, nbox, dx, dy, reverse, upsidedown,
+ bitplane, closure);
+ }
+ exaDrawableDirty (pDstDrawable);
+}
+
+static RegionPtr
+exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, exaCopyNtoN, 0, 0);
+}
+
+static void
+exaPolyFillRect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr 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;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
+ return;
+ }
+
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, 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 = REGION_NUM_RECTS (pClip);
+ if (n == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + xoff, fullY1 + yoff,
+ fullX2 + xoff, fullY2 + yoff);
+ }
+ else
+ {
+ pbox = REGION_RECTS(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect()
+ */
+ 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->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaSolidBoxClipped (DrawablePtr pDrawable,
+ RegionPtr pClip,
+ FbBits pm,
+ FbBits fg,
+ int x1,
+ int y1,
+ int x2,
+ int y2)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int partX1, partX2, partY1, partY2;
+
+ STRACE;
+ if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, pm, fg))
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
+ fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
+ fbAnd (GXcopy, fg, pm),
+ fbXor (GXcopy, fg, pm));
+ exaDrawableDirty (pDrawable);
+ return;
+ }
+ for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < x1)
+ partX1 = x1;
+
+ partX2 = pbox->x2;
+ if (partX2 > x2)
+ partX2 = x2;
+
+ if (partX2 <= partX1)
+ continue;
+
+ partY1 = pbox->y1;
+ if (partY1 < y1)
+ partY1 = y1;
+
+ partY2 = pbox->y2;
+ if (partY2 > y2)
+ partY2 = y2;
+
+ if (partY2 <= partY1)
+ continue;
+
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ CharInfoPtr *ppci;
+ CharInfoPtr pci;
+ unsigned char *pglyph; /* pointer bits in glyph */
+ int gWidth, gHeight; /* width and height of glyph */
+ FbStride gStride; /* stride of glyph */
+ Bool opaque;
+ int n;
+ int gx, gy;
+ void (*glyph) (FbBits *,
+ FbStride,
+ int,
+ FbStip *,
+ FbBits,
+ int,
+ int);
+ FbBits *dst;
+ FbStride dstStride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+ FbBits depthMask;
+
+ STRACE;
+ depthMask = FbFullMask(pDrawable->depth);
+ if ((pGC->planemask & depthMask) != depthMask)
+ {
+ ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+ return;
+ }
+ glyph = 0;
+ fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ switch (dstBpp) {
+ case 8: glyph = fbGlyph8; break;
+ case 16: glyph = fbGlyph16; break;
+ case 24: glyph = fbGlyph24; break;
+ case 32: glyph = fbGlyph32; break;
+ }
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ if (TERMINALFONT (pGC->font) && !glyph)
+ {
+ opaque = TRUE;
+ }
+ else
+ {
+ int xBack, widthBack;
+ int yBack, heightBack;
+
+ ppci = ppciInit;
+ n = nglyph;
+ widthBack = 0;
+ while (n--)
+ widthBack += (*ppci++)->metrics.characterWidth;
+
+ xBack = x;
+ if (widthBack < 0)
+ {
+ xBack += widthBack;
+ widthBack = -widthBack;
+ }
+ yBack = y - FONTASCENT(pGC->font);
+ heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ exaSolidBoxClipped (pDrawable,
+ fbGetCompositeClip(pGC),
+ pGC->planemask,
+ pGC->bgPixel,
+ xBack,
+ yBack,
+ xBack + widthBack,
+ yBack + heightBack);
+ opaque = FALSE;
+ }
+
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+
+ ppci = ppciInit;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ gWidth = GLYPHWIDTHPIXELS(pci);
+ gHeight = GLYPHHEIGHTPIXELS(pci);
+ if (gWidth && gHeight)
+ {
+ gx = x + pci->metrics.leftSideBearing;
+ gy = y - pci->metrics.ascent;
+ if (glyph && gWidth <= sizeof (FbStip) * 8 &&
+ fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
+ {
+ (*glyph) (dst + (gy + dstYoff) * dstStride,
+ dstStride,
+ dstBpp,
+ (FbStip *) pglyph,
+ pPriv->fg,
+ gx + dstXoff,
+ gHeight);
+ }
+ else
+ {
+ gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
+ fbPutXYImage (pDrawable,
+ fbGetCompositeClip(pGC),
+ pPriv->fg,
+ pPriv->bg,
+ pPriv->pm,
+ GXcopy,
+ opaque,
+
+ gx,
+ gy,
+ gWidth, gHeight,
+
+ (FbStip *) pglyph,
+ gStride,
+ 0);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+}
+
+static const GCOps exaOps = {
+ exaFillSpans,
+ ExaCheckSetSpans,
+ ExaCheckPutImage,
+ exaCopyArea,
+ ExaCheckCopyPlane,
+ ExaCheckPolyPoint,
+ ExaCheckPolylines,
+ ExaCheckPolySegment,
+ miPolyRectangle,
+ ExaCheckPolyArc,
+ miFillPolygon,
+ exaPolyFillRect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ exaImageGlyphBlt,
+ ExaCheckPolyGlyphBlt,
+ ExaCheckPushPixels,
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+static void
+exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ fbValidateGC (pGC, changes, pDrawable);
+
+ if (exaDrawableIsOffscreen (pDrawable))
+ pGC->ops = (GCOps *) &exaOps;
+ else
+ pGC->ops = (GCOps *) &exaAsyncPixmapGCOps;
+}
+
+GCFuncs exaGCFuncs = {
+ exaValidateGC,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+static int
+exaCreateGC (GCPtr pGC)
+{
+ STRACE;
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ pGC->funcs = &exaGCFuncs;
+
+ return TRUE;
+}
+
+
+static void
+exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+ STRACE;
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+#ifdef COMPOSITE
+ if (pPixmap->screen_x || pPixmap->screen_y)
+ REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+ fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ 0,
+ &rgnDst, dx, dy, exaCopyNtoN, 0, 0);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+static void
+exaFillRegionSolid (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ Pixel pixel)
+{
+ ExaScreenPriv(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ int xoff, yoff;
+
+ STRACE;
+ if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
+ (*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel))
+ {
+ int nbox = REGION_NUM_RECTS (pRegion);
+ BoxPtr pBox = REGION_RECTS (pRegion);
+
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ pBox->x1 + xoff, pBox->y1 + yoff,
+ pBox->x2 + xoff, pBox->y2 + yoff);
+ pBox++;
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaMarkSync(pDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fbFillRegionSolid (pDrawable, pRegion, 0,
+ fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
+ }
+ exaDrawableDirty (pDrawable);
+}
+
+static void
+exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ STRACE;
+ if (!REGION_NUM_RECTS(pRegion))
+ return;
+ switch (what) {
+ case PW_BACKGROUND:
+ switch (pWin->backgroundState) {
+ case None:
+ return;
+ case ParentRelative:
+ do {
+ pWin = pWin->parent;
+ } while (pWin->backgroundState == ParentRelative);
+ (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
+ what);
+ return;
+ case BackgroundPixel:
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel);
+ return;
+#if 0
+ case BackgroundPixmap:
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap);
+ return;
+#endif
+ }
+ break;
+ case PW_BORDER:
+ if (pWin->borderIsPixel)
+ {
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel);
+ return;
+ }
+#if 0
+ else
+ {
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap);
+ return;
+ }
+#endif
+ break;
+ }
+ ExaCheckPaintWindow (pWin, pRegion, what);
+}
+
+Bool
+exaDriverInit (ScreenPtr pScreen,
+ ExaDriverPtr pScreenInfo)
+{
+ ExaScreenPrivPtr pExaScr;
+
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+ STRACE;
+ if (exaGeneration != serverGeneration)
+ {
+ exaScreenPrivateIndex = AllocateScreenPrivateIndex();
+ exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
+ exaGeneration = serverGeneration;
+ }
+
+ pExaScr = xalloc (sizeof (ExaScreenPrivRec));
+
+ if (!pExaScr)
+ return FALSE;
+
+ pExaScr->info = pScreenInfo;
+
+ pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
+
+ /*
+ * Hook up asynchronous drawing
+ */
+ ExaScreenInitAsync (pScreen);
+ /*
+ * Replace various fb screen functions
+ */
+ pScreen->CreateGC = exaCreateGC;
+ pScreen->CopyWindow = exaCopyWindow;
+ pScreen->PaintWindowBackground = exaPaintWindow;
+ pScreen->PaintWindowBorder = exaPaintWindow;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = exaComposite;
+ }
+#endif
+
+ /*
+ * Hookup offscreen pixmaps
+ */
+ if ((pExaScr->info->card.flags & EXA_OFFSCREEN_PIXMAPS) &&
+ pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize)
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
+ sizeof (ExaPixmapPrivRec)))
+ return FALSE;
+ pScreen->CreatePixmap = exaCreatePixmap;
+ pScreen->DestroyPixmap = exaDestroyPixmap;
+ }
+ else
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
+ return FALSE;
+ }
+
+ ErrorF("============== %ld < %ld\n", pExaScr->info->card.offScreenBase,
+ pExaScr->info->card.memorySize);
+ if (pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize) {
+ if (!exaOffscreenInit (pScreen))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+exaDriverFini (ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ xfree (pExaScr);
+}
+
+
+void exaMarkSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ card->needsSync = TRUE;
+ if (pExaScr->info->accel.MarkSync != NULL) {
+ card->lastMarker = (*pExaScr->info->accel.MarkSync)(pScreen);
+ }
+}
+
+void exaWaitSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ if (card->needsSync) {
+ (*pExaScr->info->accel.WaitMarker)(pScreen, card->lastMarker);
+ card->needsSync = FALSE;
+ }
+}
+
+unsigned int exaGetVersion(void)
+{
+ return EXA_VERSION;
+}
+
+#ifdef XFree86LOADER
+static MODULESETUPPROTO(exaSetup);
+
+
+static const OptionInfoRec EXAOptions[] = {
+ { -1, NULL,
+ OPTV_NONE, {0}, FALSE }
+};
+
+/*ARGSUSED*/
+static const OptionInfoRec *
+EXAAvailableOptions(void *unused)
+{
+ return (EXAOptions);
+}
+
+static XF86ModuleVersionInfo exaVersRec =
+{
+ "exa",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 2, 0,
+ ABI_CLASS_VIDEODRV, /* requires the video driver ABI */
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ {0,0,0,0}
+};
+
+XF86ModuleData exaModuleData = { &exaVersRec, exaSetup, NULL };
+
+ModuleInfoRec EXA = {
+ 1,
+ "EXA",
+ NULL,
+ 0,
+ EXAAvailableOptions,
+};
+
+/*ARGSUSED*/
+static pointer
+exaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
+{
+ static Bool Initialised = FALSE;
+
+ ErrorF("exa setup\n");
+ if (!Initialised) {
+ Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+ if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+ xf86AddModuleInfo(&EXA, Module);
+ }
+
+ return (pointer)TRUE;
+}
+#endif
diff --git a/exa/exa.h b/exa/exa.h
new file mode 100644
index 000000000..15945c1f1
--- /dev/null
+++ b/exa/exa.h
@@ -0,0 +1,240 @@
+/*
+ *
+ * Copyright (C) 2000 Keith Packard
+ * 2004 Eric Anholt
+ * 2005 Zack Rusin
+ *
+ * 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 copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Copyright holders make no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ */
+#ifndef EXA_H
+#define EXA_H
+
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "picturestr.h"
+
+#define EXA_VERSION_MAJOR 0
+#define EXA_VERSION_MINOR 1
+#define EXA_VERSION_RELEASE 0
+
+typedef struct _ExaOffscreenArea ExaOffscreenArea;
+
+typedef void (*ExaOffscreenSaveProc) (ScreenPtr pScreen, ExaOffscreenArea *area);
+
+typedef enum _ExaOffscreenState {
+ ExaOffscreenAvail,
+ ExaOffscreenRemovable,
+ ExaOffscreenLocked
+} ExaOffscreenState;
+
+struct _ExaOffscreenArea {
+ int offset;
+ int save_offset;
+ int size;
+ int score;
+ pointer privData;
+
+ ExaOffscreenSaveProc save;
+
+ ExaOffscreenState state;
+
+ ExaOffscreenArea *next;
+};
+
+typedef struct _ExaCardInfo {
+ /* These are here because I don't want to be adding more to
+ * ScrnInfoRec */
+ CARD8 *memoryBase;
+ unsigned long offScreenBase;
+
+ /* It's fix.smem_len.
+ This one could be potentially substituted by ScrnInfoRec
+ videoRam member, but I do not want to be doing the silly
+ << 10, >>10 all over the place */
+ unsigned long memorySize;
+
+ int offscreenByteAlign;
+ int offscreenPitch;
+ int flags;
+
+ /* The coordinate limitations for rendering for this hardware.
+ * Exa breaks larger pixmaps into smaller pieces and calls Prepare multiple times
+ * to handle larger pixmaps
+ */
+ int maxX;
+ int maxY;
+
+ /* private */
+ ExaOffscreenArea *offScreenAreas;
+ Bool needsSync;
+ int lastMarker;
+} ExaCardInfoRec, *ExaCardInfoPtr;
+
+typedef struct _ExaAccelInfo {
+ /* PrepareSolid may fail if the pixmaps can't be accelerated to/from.
+ * This is an important feature for handling strange corner cases
+ * in hardware that are poorly expressed through flags.
+ */
+ Bool (*PrepareSolid) (PixmapPtr pPixmap,
+ int alu,
+ Pixel planemask,
+ Pixel fg);
+ void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
+ void (*DoneSolid) (PixmapPtr pPixmap);
+
+ /* PrepareSolid may fail if the pixmaps can't be accelerated to/from.
+ * This is an important feature for handling strange corner cases
+ * in hardware that are poorly expressed through flags.
+ */
+ Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ Bool upsidedown,
+ Bool reverse,
+ int alu,
+ Pixel planemask);
+ void (*Copy) (PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+ void (*DoneCopy) (PixmapPtr pDstPixmap);
+
+ /* The Composite hooks are a wrapper around the Composite operation.
+ * The CheckComposite occurs before pixmap migration occurs,
+ * and may fail for many hardware-dependent reasons.
+ * PrepareComposite should not fail, and the Bool return may
+ * not be necessary if we can
+ * adequately represent pixmap location/pitch limitations..
+ */
+ Bool (*CheckComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture);
+ Bool (*PrepareComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask,
+ PixmapPtr pDst);
+ void (*Composite) (PixmapPtr pDst,
+ int srcX,
+ int srcY,
+ int maskX,
+ int maskY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+ void (*DoneComposite) (PixmapPtr pDst);
+
+ /* Attempt to upload the data from src into the rectangle of the
+ * in-framebuffer pDst beginning at x,y and of width w,h. May fail.
+ */
+ Bool (*UploadToScreen) (PixmapPtr pDst,
+ char *src,
+ int src_pitch);
+ Bool (*UploadToScratch) (PixmapPtr pSrc,
+ PixmapPtr pDst);
+
+ /* Attempt to download the rectangle from the in-framebuffer pSrc into
+ * dst, given the pitch. May fail. Since it is likely
+ * accelerated, a markSync will follow it as with other acceleration
+ * hooks.
+ */
+ Bool (*DownloadFromScreen)(PixmapPtr pSrc,
+ int x, int y,
+ int w, int h,
+ char *dst, int dst_pitch);
+
+ /* Should return a hrdware-dependent marker number which can
+ * be waited for with WaitMarker. It can be not implemented in which
+ * case WaitMarker must wait for idle on any given marker
+ * number.
+ */
+ int (*MarkSync) (ScreenPtr pScreen);
+ void (*WaitMarker) (ScreenPtr pScreen, int marker);
+} ExaAccelInfoRec, *ExaAccelInfoPtr;
+
+typedef struct _ExaDriver {
+ ExaCardInfoRec card;
+ ExaAccelInfoRec accel;
+} ExaDriverRec, *ExaDriverPtr;
+
+typedef struct {
+ ExaDriverPtr info;
+} ExaScreenPrivRec, *ExaScreenPrivPtr;
+
+#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
+#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
+
+
+#define EXA_MAKE_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
+#define EXA_VERSION \
+ EXA_MAKE_VERSION(EXA_VERSION_MAJOR, EXA_VERSION_MINOR, EXA_VERSION_RELEASE)
+#define EXA_IS_VERSION(a,b,c) (EXA_VERSION >= EXA_MAKE_VERSION(a,b,c))
+
+unsigned int
+exaGetVersion(void);
+
+Bool
+exaDriverInit(ScreenPtr pScreen,
+ ExaDriverPtr pScreenInfo);
+
+void
+exaDriverFini(ScreenPtr pScreen);
+
+void
+exaMarkSync(ScreenPtr pScreen);
+void
+exaWaitSync(ScreenPtr pScreen);
+
+Bool
+exaOffscreenInit(ScreenPtr pScreen);
+
+ExaOffscreenArea *
+exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
+ Bool locked,
+ ExaOffscreenSaveProc save,
+ pointer privData);
+
+ExaOffscreenArea *
+exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea *area);
+
+
+
+#define exaInitCard(exa, sync, memory_base, off_screen_base, memory_size, \
+ offscreen_byte_align, offscreen_pitch, flags, \
+ max_x, max_y) \
+ (exa)->card.Sync = sync; \
+ (exa)->card.memoryBase = memory_base; \
+ (exa)->card.offScreenBase = off_screen_base; \
+ (exa)->card.memorySize = memory_size; \
+ (exa)->card.offscreenByteAlign = offscreen_byte_align; \
+ (exa)->card.offscreenPitch = offscreen_pitch; \
+ (exa)->card.flags = flags; \
+ (exa)->card.maxX = max_x; \
+ (exa)->card.maxY = max_y
+
+#endif /* EXA_H */
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
new file mode 100644
index 000000000..c2d0db063
--- /dev/null
+++ b/exa/exa_accel.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "exaPriv.h"
+#include "fontstruct.h"
+#include "dixfontstr.h"
+#include "xf86str.h"
+#include "xf86.h"
+#include "exa.h"
+
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#if DEBUG_MIGRATE
+#define DBG_MIGRATE(a) ErrorF a
+#else
+#define DBG_MIGRATE(a)
+#endif
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+#define STRACE
+#define TRACE
+
+int exaGeneration;
+int exaScreenPrivateIndex;
+int exaPixmapPrivateIndex;
+
+#define EXA_PIXMAP_SCORE_MOVE_IN 10
+#define EXA_PIXMAP_SCORE_MAX 20
+#define EXA_PIXMAP_SCORE_MOVE_OUT -10
+#define EXA_PIXMAP_SCORE_MIN -20
+#define EXA_PIXMAP_SCORE_PINNED 1000
+#define EXA_PIXMAP_SCORE_INIT 1001
+
+void
+exaDrawableDirty (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap)((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr)pDrawable;
+
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (pExaPixmap != NULL)
+ pExaPixmap->dirty = TRUE;
+}
+
+static void
+exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ PixmapPtr pPixmap = area->privData;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv(pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("Save 0x%08p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src_pitch = pPixmap->devKind;
+ dst_pitch = pExaPixmap->devKind;
+
+ src = pPixmap->devPrivate.ptr;
+ dst = pExaPixmap->devPrivate.ptr;
+
+ if (pExaScr->info->accel.DownloadFromScreen)
+ {
+ if (pExaScr->info->accel.DownloadFromScreen(pPixmap,
+ pPixmap->drawable.x,
+ pPixmap->drawable.y,
+ pPixmap->drawable.width,
+ pPixmap->drawable.height,
+ dst,
+ dst_pitch)) {
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+ return;
+ }
+ }
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+
+#if 0
+ if (!pExaPixmap->dirty)
+ return;
+#endif
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ i = pPixmap->drawable.height;
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+}
+
+static int
+exaLog2(int val)
+{
+ int bits;
+
+ if (!val)
+ return 0;
+ for (bits = 0; val != 0; bits++)
+ val >>= 1;
+ return bits - 1;
+}
+
+static Bool
+exaPixmapAllocArea (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int bpp = pPixmap->drawable.bitsPerPixel;
+ CARD16 h = pPixmap->drawable.height;
+ CARD16 w = pPixmap->drawable.width;
+ int pitch;
+
+ if (pExaScr->info->card.flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
+ w = 1 << (exaLog2(w - 1) + 1);
+ pitch = (w * bpp / 8 + pExaScr->info->card.offscreenPitch - 1) &
+ ~(pExaScr->info->card.offscreenPitch - 1);
+
+ pExaPixmap->devKind = pPixmap->devKind;
+ pExaPixmap->devPrivate = pPixmap->devPrivate;
+ pExaPixmap->area = exaOffscreenAlloc (pScreen, pitch * h,
+ pExaScr->info->card.offscreenByteAlign,
+ FALSE,
+ exaPixmapSave, (pointer) pPixmap);
+ if (!pExaPixmap->area)
+ return FALSE;
+
+ DBG_PIXMAP(("++ 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ pPixmap->devKind = pitch;
+
+ pPixmap->devPrivate.ptr = (pointer) ((CARD8 *) pExaScr->info->card.memoryBase + pExaPixmap->area->offset);
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ return TRUE;
+}
+
+void
+exaMoveInPixmap (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("-> 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src = pPixmap->devPrivate.ptr;
+ src_pitch = pPixmap->devKind;
+
+ if (!exaPixmapAllocArea (pPixmap))
+ return;
+
+ pExaPixmap->dirty = FALSE;
+
+ if (pExaScr->info->accel.UploadToScreen)
+ {
+ if (pExaScr->info->accel.UploadToScreen(pPixmap, src, src_pitch))
+ return;
+ }
+
+ dst = pPixmap->devPrivate.ptr;
+ dst_pitch = pPixmap->devKind;
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ i = pPixmap->drawable.height;
+ ErrorF("dst = %p, src = %p,(%d, %d) height = %d, mem_base = %p, offset = %d\n",
+ dst, src, dst_pitch, src_pitch,
+ i, pExaScr->info->card.memoryBase, ExaGetPixmapPriv(pPixmap)->area->offset);
+
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ ErrorF("done\n");
+}
+
+static void
+exaMoveOutPixmap (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+ ExaOffscreenArea *area = pExaPixmap->area;
+
+ DBG_MIGRATE (("<- 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ STRACE;
+ if (area)
+ {
+ exaPixmapSave (pPixmap->drawable.pScreen, area);
+ exaOffscreenFree (pPixmap->drawable.pScreen, area);
+ }
+}
+
+void
+exaPixmapUseScreen (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ STRACE;
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+ return;
+
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
+ exaMoveInPixmap(pPixmap);
+ pExaPixmap->score = 0;
+ }
+
+ if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
+ {
+ pExaPixmap->score++;
+ if (!exaPixmapIsOffscreen(pPixmap) &&
+ pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN)
+ exaMoveInPixmap (pPixmap);
+ }
+ ExaOffscreenMarkUsed (pPixmap);
+}
+
+void
+exaPixmapUseMemory (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ 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->area &&
+ pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT)
+ exaMoveOutPixmap (pPixmap);
+ }
+}
+
+static Bool
+exaDestroyPixmap (PixmapPtr pPixmap)
+{
+ if (pPixmap->refcnt == 1)
+ {
+ ExaPixmapPriv (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 = pExaPixmap->devPrivate;
+ pPixmap->devKind = pExaPixmap->devKind;
+ }
+ }
+ return fbDestroyPixmap (pPixmap);
+}
+
+static PixmapPtr
+exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+ int bpp;
+
+ bpp = BitsPerPixel (depth);
+ if (bpp == 32 && depth == 24)
+ {
+ int format;
+ ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
+ for (format = 0; format < MAXFORMATS && pScrn->formats[format].depth; ++format)
+ if (pScrn->formats[format].depth == 24)
+ {
+ bpp = pScrn->formats[format].bitsPerPixel;
+ break;
+ }
+ }
+
+ pPixmap = fbCreatePixmapBpp (pScreen, w, h, depth, bpp);
+ if (!pPixmap)
+ return NULL;
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (!w || !h)
+ pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+ else
+ pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+
+ pExaPixmap->area = NULL;
+ pExaPixmap->dirty = FALSE;
+
+ return pPixmap;
+}
+
+Bool
+exaPixmapIsOffscreen(PixmapPtr p)
+{
+ ScreenPtr pScreen = p->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
+ (CARD8 *) pExaScr->info->card.memoryBase) <
+ pExaScr->info->card.memorySize);
+}
+
+PixmapPtr
+exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
+{
+ PixmapPtr pPixmap;
+ int x, y;
+
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+#ifdef COMPOSITE
+ x = -pPixmap->screen_x;
+ y = -pPixmap->screen_y;
+#else
+ x = 0;
+ y = 0;
+#endif
+ }
+ else
+ {
+ pPixmap = (PixmapPtr) pDrawable;
+ x = 0;
+ y = 0;
+ }
+ *xp = x;
+ *yp = y;
+ if (exaPixmapIsOffscreen (pPixmap))
+ return pPixmap;
+ else
+ return NULL;
+}
+
+Bool
+exaDrawableIsOffscreen (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr) pDrawable;
+ return exaPixmapIsOffscreen (pPixmap);
+}
+
+#if 0
+static void
+exaFillTiled(int dst_x,
+ int dst_y,
+ int width,
+ int height,
+ int src_x,
+ int src_y,
+ int src_width,
+ int src_height,
+ void (*Copy) (int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height))
+{
+ modulus (src_x, src_width, src_x);
+ modulus (src_y, src_height, src_y);
+
+ while (height)
+ {
+ int dst_x_tmp = dst_x;
+ int src_x_tmp = src_x;
+ int width_tmp = width;
+ int height_left = src_height - src_y;
+ int height_this = min (height, height_left);
+
+ while (width_tmp)
+ {
+ int width_left = src_width - src_x_tmp;
+ int width_this = min (width_tmp, width_left);
+
+ (*Copy) (src_x_tmp, src_y,
+ dst_x_tmp, dst_y,
+ width_this, height_this);
+
+ width_tmp -= width_this;
+ dst_x_tmp += width_this;
+ }
+ height -= height_this;
+ dst_y += height_this;
+ src_y = 0;
+ }
+}
+#endif
+
+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;
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (n--)
+ {
+ fullX1 = ppt->x;
+ fullY1 = ppt->y;
+ fullX2 = fullX1 + (int) *pwidth;
+ ppt++;
+ pwidth++;
+
+ if (fullY1 < extentY1 || extentY2 <= fullY1)
+ continue;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullX1 >= fullX2)
+ continue;
+
+ nbox = REGION_NUM_RECTS (pClip);
+ if (nbox == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + off_x, fullY1 + off_y,
+ fullX2 + off_x, fullY1 + 1 + off_y);
+ }
+ else
+ {
+ pbox = REGION_RECTS(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->accel.Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ pbox++;
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pScreen);
+}
+
+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);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ STRACE;
+
+ /* Migrate pixmaps to same place as destination */
+ if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
+ if (exaDrawableIsOffscreen (pDstDrawable))
+ exaPixmapUseScreen ((PixmapPtr) pSrcDrawable);
+ else
+ exaPixmapUseMemory ((PixmapPtr) pSrcDrawable);
+ }
+
+ if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
+ (pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
+ (*pExaScr->info->accel.PrepareCopy) (pSrcPixmap,
+ pDstPixmap,
+ dx,
+ dy,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES))
+ {
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.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->accel.DoneCopy) (pDstPixmap);
+ exaMarkSync(pDstDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDstDrawable->pScreen);
+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
+ pbox, nbox, dx, dy, reverse, upsidedown,
+ bitplane, closure);
+ }
+ exaDrawableDirty (pDstDrawable);
+}
+
+static RegionPtr
+exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, exaCopyNtoN, 0, 0);
+}
+
+static void
+exaPolyFillRect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr 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;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
+ return;
+ }
+
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, 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 = REGION_NUM_RECTS (pClip);
+ if (n == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + xoff, fullY1 + yoff,
+ fullX2 + xoff, fullY2 + yoff);
+ }
+ else
+ {
+ pbox = REGION_RECTS(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect()
+ */
+ 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->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaSolidBoxClipped (DrawablePtr pDrawable,
+ RegionPtr pClip,
+ FbBits pm,
+ FbBits fg,
+ int x1,
+ int y1,
+ int x2,
+ int y2)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int partX1, partX2, partY1, partY2;
+
+ STRACE;
+ if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, pm, fg))
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
+ fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
+ fbAnd (GXcopy, fg, pm),
+ fbXor (GXcopy, fg, pm));
+ exaDrawableDirty (pDrawable);
+ return;
+ }
+ for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < x1)
+ partX1 = x1;
+
+ partX2 = pbox->x2;
+ if (partX2 > x2)
+ partX2 = x2;
+
+ if (partX2 <= partX1)
+ continue;
+
+ partY1 = pbox->y1;
+ if (partY1 < y1)
+ partY1 = y1;
+
+ partY2 = pbox->y2;
+ if (partY2 > y2)
+ partY2 = y2;
+
+ if (partY2 <= partY1)
+ continue;
+
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ CharInfoPtr *ppci;
+ CharInfoPtr pci;
+ unsigned char *pglyph; /* pointer bits in glyph */
+ int gWidth, gHeight; /* width and height of glyph */
+ FbStride gStride; /* stride of glyph */
+ Bool opaque;
+ int n;
+ int gx, gy;
+ void (*glyph) (FbBits *,
+ FbStride,
+ int,
+ FbStip *,
+ FbBits,
+ int,
+ int);
+ FbBits *dst;
+ FbStride dstStride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+ FbBits depthMask;
+
+ STRACE;
+ depthMask = FbFullMask(pDrawable->depth);
+ if ((pGC->planemask & depthMask) != depthMask)
+ {
+ ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+ return;
+ }
+ glyph = 0;
+ fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ switch (dstBpp) {
+ case 8: glyph = fbGlyph8; break;
+ case 16: glyph = fbGlyph16; break;
+ case 24: glyph = fbGlyph24; break;
+ case 32: glyph = fbGlyph32; break;
+ }
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ if (TERMINALFONT (pGC->font) && !glyph)
+ {
+ opaque = TRUE;
+ }
+ else
+ {
+ int xBack, widthBack;
+ int yBack, heightBack;
+
+ ppci = ppciInit;
+ n = nglyph;
+ widthBack = 0;
+ while (n--)
+ widthBack += (*ppci++)->metrics.characterWidth;
+
+ xBack = x;
+ if (widthBack < 0)
+ {
+ xBack += widthBack;
+ widthBack = -widthBack;
+ }
+ yBack = y - FONTASCENT(pGC->font);
+ heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ exaSolidBoxClipped (pDrawable,
+ fbGetCompositeClip(pGC),
+ pGC->planemask,
+ pGC->bgPixel,
+ xBack,
+ yBack,
+ xBack + widthBack,
+ yBack + heightBack);
+ opaque = FALSE;
+ }
+
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+
+ ppci = ppciInit;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ gWidth = GLYPHWIDTHPIXELS(pci);
+ gHeight = GLYPHHEIGHTPIXELS(pci);
+ if (gWidth && gHeight)
+ {
+ gx = x + pci->metrics.leftSideBearing;
+ gy = y - pci->metrics.ascent;
+ if (glyph && gWidth <= sizeof (FbStip) * 8 &&
+ fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
+ {
+ (*glyph) (dst + (gy + dstYoff) * dstStride,
+ dstStride,
+ dstBpp,
+ (FbStip *) pglyph,
+ pPriv->fg,
+ gx + dstXoff,
+ gHeight);
+ }
+ else
+ {
+ gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
+ fbPutXYImage (pDrawable,
+ fbGetCompositeClip(pGC),
+ pPriv->fg,
+ pPriv->bg,
+ pPriv->pm,
+ GXcopy,
+ opaque,
+
+ gx,
+ gy,
+ gWidth, gHeight,
+
+ (FbStip *) pglyph,
+ gStride,
+ 0);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+}
+
+static const GCOps exaOps = {
+ exaFillSpans,
+ ExaCheckSetSpans,
+ ExaCheckPutImage,
+ exaCopyArea,
+ ExaCheckCopyPlane,
+ ExaCheckPolyPoint,
+ ExaCheckPolylines,
+ ExaCheckPolySegment,
+ miPolyRectangle,
+ ExaCheckPolyArc,
+ miFillPolygon,
+ exaPolyFillRect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ exaImageGlyphBlt,
+ ExaCheckPolyGlyphBlt,
+ ExaCheckPushPixels,
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+static void
+exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ fbValidateGC (pGC, changes, pDrawable);
+
+ if (exaDrawableIsOffscreen (pDrawable))
+ pGC->ops = (GCOps *) &exaOps;
+ else
+ pGC->ops = (GCOps *) &exaAsyncPixmapGCOps;
+}
+
+GCFuncs exaGCFuncs = {
+ exaValidateGC,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+static int
+exaCreateGC (GCPtr pGC)
+{
+ STRACE;
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ pGC->funcs = &exaGCFuncs;
+
+ return TRUE;
+}
+
+
+static void
+exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+ STRACE;
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+#ifdef COMPOSITE
+ if (pPixmap->screen_x || pPixmap->screen_y)
+ REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+ fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ 0,
+ &rgnDst, dx, dy, exaCopyNtoN, 0, 0);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+static void
+exaFillRegionSolid (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ Pixel pixel)
+{
+ ExaScreenPriv(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ int xoff, yoff;
+
+ STRACE;
+ if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
+ (*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel))
+ {
+ int nbox = REGION_NUM_RECTS (pRegion);
+ BoxPtr pBox = REGION_RECTS (pRegion);
+
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ pBox->x1 + xoff, pBox->y1 + yoff,
+ pBox->x2 + xoff, pBox->y2 + yoff);
+ pBox++;
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaMarkSync(pDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fbFillRegionSolid (pDrawable, pRegion, 0,
+ fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
+ }
+ exaDrawableDirty (pDrawable);
+}
+
+static void
+exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ STRACE;
+ if (!REGION_NUM_RECTS(pRegion))
+ return;
+ switch (what) {
+ case PW_BACKGROUND:
+ switch (pWin->backgroundState) {
+ case None:
+ return;
+ case ParentRelative:
+ do {
+ pWin = pWin->parent;
+ } while (pWin->backgroundState == ParentRelative);
+ (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
+ what);
+ return;
+ case BackgroundPixel:
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel);
+ return;
+#if 0
+ case BackgroundPixmap:
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap);
+ return;
+#endif
+ }
+ break;
+ case PW_BORDER:
+ if (pWin->borderIsPixel)
+ {
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel);
+ return;
+ }
+#if 0
+ else
+ {
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap);
+ return;
+ }
+#endif
+ break;
+ }
+ ExaCheckPaintWindow (pWin, pRegion, what);
+}
+
+Bool
+exaDriverInit (ScreenPtr pScreen,
+ ExaDriverPtr pScreenInfo)
+{
+ ExaScreenPrivPtr pExaScr;
+
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+ STRACE;
+ if (exaGeneration != serverGeneration)
+ {
+ exaScreenPrivateIndex = AllocateScreenPrivateIndex();
+ exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
+ exaGeneration = serverGeneration;
+ }
+
+ pExaScr = xalloc (sizeof (ExaScreenPrivRec));
+
+ if (!pExaScr)
+ return FALSE;
+
+ pExaScr->info = pScreenInfo;
+
+ pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
+
+ /*
+ * Hook up asynchronous drawing
+ */
+ ExaScreenInitAsync (pScreen);
+ /*
+ * Replace various fb screen functions
+ */
+ pScreen->CreateGC = exaCreateGC;
+ pScreen->CopyWindow = exaCopyWindow;
+ pScreen->PaintWindowBackground = exaPaintWindow;
+ pScreen->PaintWindowBorder = exaPaintWindow;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = exaComposite;
+ }
+#endif
+
+ /*
+ * Hookup offscreen pixmaps
+ */
+ if ((pExaScr->info->card.flags & EXA_OFFSCREEN_PIXMAPS) &&
+ pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize)
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
+ sizeof (ExaPixmapPrivRec)))
+ return FALSE;
+ pScreen->CreatePixmap = exaCreatePixmap;
+ pScreen->DestroyPixmap = exaDestroyPixmap;
+ }
+ else
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
+ return FALSE;
+ }
+
+ ErrorF("============== %ld < %ld\n", pExaScr->info->card.offScreenBase,
+ pExaScr->info->card.memorySize);
+ if (pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize) {
+ if (!exaOffscreenInit (pScreen))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+exaDriverFini (ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ xfree (pExaScr);
+}
+
+
+void exaMarkSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ card->needsSync = TRUE;
+ if (pExaScr->info->accel.MarkSync != NULL) {
+ card->lastMarker = (*pExaScr->info->accel.MarkSync)(pScreen);
+ }
+}
+
+void exaWaitSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ if (card->needsSync) {
+ (*pExaScr->info->accel.WaitMarker)(pScreen, card->lastMarker);
+ card->needsSync = FALSE;
+ }
+}
+
+unsigned int exaGetVersion(void)
+{
+ return EXA_VERSION;
+}
+
+#ifdef XFree86LOADER
+static MODULESETUPPROTO(exaSetup);
+
+
+static const OptionInfoRec EXAOptions[] = {
+ { -1, NULL,
+ OPTV_NONE, {0}, FALSE }
+};
+
+/*ARGSUSED*/
+static const OptionInfoRec *
+EXAAvailableOptions(void *unused)
+{
+ return (EXAOptions);
+}
+
+static XF86ModuleVersionInfo exaVersRec =
+{
+ "exa",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 2, 0,
+ ABI_CLASS_VIDEODRV, /* requires the video driver ABI */
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ {0,0,0,0}
+};
+
+XF86ModuleData exaModuleData = { &exaVersRec, exaSetup, NULL };
+
+ModuleInfoRec EXA = {
+ 1,
+ "EXA",
+ NULL,
+ 0,
+ EXAAvailableOptions,
+};
+
+/*ARGSUSED*/
+static pointer
+exaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
+{
+ static Bool Initialised = FALSE;
+
+ ErrorF("exa setup\n");
+ if (!Initialised) {
+ Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+ if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+ xf86AddModuleInfo(&EXA, Module);
+ }
+
+ return (pointer)TRUE;
+}
+#endif
diff --git a/exa/exa_migration.c b/exa/exa_migration.c
new file mode 100644
index 000000000..c2d0db063
--- /dev/null
+++ b/exa/exa_migration.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "exaPriv.h"
+#include "fontstruct.h"
+#include "dixfontstr.h"
+#include "xf86str.h"
+#include "xf86.h"
+#include "exa.h"
+
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#if DEBUG_MIGRATE
+#define DBG_MIGRATE(a) ErrorF a
+#else
+#define DBG_MIGRATE(a)
+#endif
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+#define STRACE
+#define TRACE
+
+int exaGeneration;
+int exaScreenPrivateIndex;
+int exaPixmapPrivateIndex;
+
+#define EXA_PIXMAP_SCORE_MOVE_IN 10
+#define EXA_PIXMAP_SCORE_MAX 20
+#define EXA_PIXMAP_SCORE_MOVE_OUT -10
+#define EXA_PIXMAP_SCORE_MIN -20
+#define EXA_PIXMAP_SCORE_PINNED 1000
+#define EXA_PIXMAP_SCORE_INIT 1001
+
+void
+exaDrawableDirty (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap)((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr)pDrawable;
+
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (pExaPixmap != NULL)
+ pExaPixmap->dirty = TRUE;
+}
+
+static void
+exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ PixmapPtr pPixmap = area->privData;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv(pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("Save 0x%08p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src_pitch = pPixmap->devKind;
+ dst_pitch = pExaPixmap->devKind;
+
+ src = pPixmap->devPrivate.ptr;
+ dst = pExaPixmap->devPrivate.ptr;
+
+ if (pExaScr->info->accel.DownloadFromScreen)
+ {
+ if (pExaScr->info->accel.DownloadFromScreen(pPixmap,
+ pPixmap->drawable.x,
+ pPixmap->drawable.y,
+ pPixmap->drawable.width,
+ pPixmap->drawable.height,
+ dst,
+ dst_pitch)) {
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+ return;
+ }
+ }
+
+ pPixmap->devKind = dst_pitch;
+ pPixmap->devPrivate.ptr = dst;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ pExaPixmap->area = NULL;
+
+#if 0
+ if (!pExaPixmap->dirty)
+ return;
+#endif
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ i = pPixmap->drawable.height;
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+}
+
+static int
+exaLog2(int val)
+{
+ int bits;
+
+ if (!val)
+ return 0;
+ for (bits = 0; val != 0; bits++)
+ val >>= 1;
+ return bits - 1;
+}
+
+static Bool
+exaPixmapAllocArea (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int bpp = pPixmap->drawable.bitsPerPixel;
+ CARD16 h = pPixmap->drawable.height;
+ CARD16 w = pPixmap->drawable.width;
+ int pitch;
+
+ if (pExaScr->info->card.flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
+ w = 1 << (exaLog2(w - 1) + 1);
+ pitch = (w * bpp / 8 + pExaScr->info->card.offscreenPitch - 1) &
+ ~(pExaScr->info->card.offscreenPitch - 1);
+
+ pExaPixmap->devKind = pPixmap->devKind;
+ pExaPixmap->devPrivate = pPixmap->devPrivate;
+ pExaPixmap->area = exaOffscreenAlloc (pScreen, pitch * h,
+ pExaScr->info->card.offscreenByteAlign,
+ FALSE,
+ exaPixmapSave, (pointer) pPixmap);
+ if (!pExaPixmap->area)
+ return FALSE;
+
+ DBG_PIXMAP(("++ 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ pPixmap->devKind = pitch;
+
+ pPixmap->devPrivate.ptr = (pointer) ((CARD8 *) pExaScr->info->card.memoryBase + pExaPixmap->area->offset);
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ return TRUE;
+}
+
+void
+exaMoveInPixmap (PixmapPtr pPixmap)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ExaScreenPriv (pScreen);
+ ExaPixmapPriv (pPixmap);
+ int dst_pitch, src_pitch, bytes;
+ char *dst, *src;
+ int i;
+
+ DBG_MIGRATE (("-> 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+
+ src = pPixmap->devPrivate.ptr;
+ src_pitch = pPixmap->devKind;
+
+ if (!exaPixmapAllocArea (pPixmap))
+ return;
+
+ pExaPixmap->dirty = FALSE;
+
+ if (pExaScr->info->accel.UploadToScreen)
+ {
+ if (pExaScr->info->accel.UploadToScreen(pPixmap, src, src_pitch))
+ return;
+ }
+
+ dst = pPixmap->devPrivate.ptr;
+ dst_pitch = pPixmap->devKind;
+
+ bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
+
+ exaWaitSync (pPixmap->drawable.pScreen);
+
+ i = pPixmap->drawable.height;
+ ErrorF("dst = %p, src = %p,(%d, %d) height = %d, mem_base = %p, offset = %d\n",
+ dst, src, dst_pitch, src_pitch,
+ i, pExaScr->info->card.memoryBase, ExaGetPixmapPriv(pPixmap)->area->offset);
+
+ while (i--) {
+ memcpy (dst, src, bytes);
+ dst += dst_pitch;
+ src += src_pitch;
+ }
+ ErrorF("done\n");
+}
+
+static void
+exaMoveOutPixmap (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+ ExaOffscreenArea *area = pExaPixmap->area;
+
+ DBG_MIGRATE (("<- 0x%p (0x%p) (%dx%d)\n",
+ (void*)pPixmap->drawable.id,
+ (void*)(ExaGetPixmapPriv(pPixmap)->area ?
+ ExaGetPixmapPriv(pPixmap)->area->offset : 0),
+ pPixmap->drawable.width,
+ pPixmap->drawable.height));
+ STRACE;
+ if (area)
+ {
+ exaPixmapSave (pPixmap->drawable.pScreen, area);
+ exaOffscreenFree (pPixmap->drawable.pScreen, area);
+ }
+}
+
+void
+exaPixmapUseScreen (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ STRACE;
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
+ return;
+
+ if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
+ exaMoveInPixmap(pPixmap);
+ pExaPixmap->score = 0;
+ }
+
+ if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
+ {
+ pExaPixmap->score++;
+ if (!exaPixmapIsOffscreen(pPixmap) &&
+ pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN)
+ exaMoveInPixmap (pPixmap);
+ }
+ ExaOffscreenMarkUsed (pPixmap);
+}
+
+void
+exaPixmapUseMemory (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+
+ 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->area &&
+ pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT)
+ exaMoveOutPixmap (pPixmap);
+ }
+}
+
+static Bool
+exaDestroyPixmap (PixmapPtr pPixmap)
+{
+ if (pPixmap->refcnt == 1)
+ {
+ ExaPixmapPriv (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 = pExaPixmap->devPrivate;
+ pPixmap->devKind = pExaPixmap->devKind;
+ }
+ }
+ return fbDestroyPixmap (pPixmap);
+}
+
+static PixmapPtr
+exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
+{
+ PixmapPtr pPixmap;
+ ExaPixmapPrivPtr pExaPixmap;
+ int bpp;
+
+ bpp = BitsPerPixel (depth);
+ if (bpp == 32 && depth == 24)
+ {
+ int format;
+ ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
+ for (format = 0; format < MAXFORMATS && pScrn->formats[format].depth; ++format)
+ if (pScrn->formats[format].depth == 24)
+ {
+ bpp = pScrn->formats[format].bitsPerPixel;
+ break;
+ }
+ }
+
+ pPixmap = fbCreatePixmapBpp (pScreen, w, h, depth, bpp);
+ if (!pPixmap)
+ return NULL;
+ pExaPixmap = ExaGetPixmapPriv(pPixmap);
+ if (!w || !h)
+ pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
+ else
+ pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
+
+ pExaPixmap->area = NULL;
+ pExaPixmap->dirty = FALSE;
+
+ return pPixmap;
+}
+
+Bool
+exaPixmapIsOffscreen(PixmapPtr p)
+{
+ ScreenPtr pScreen = p->drawable.pScreen;
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ return ((unsigned long) ((CARD8 *) p->devPrivate.ptr -
+ (CARD8 *) pExaScr->info->card.memoryBase) <
+ pExaScr->info->card.memorySize);
+}
+
+PixmapPtr
+exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
+{
+ PixmapPtr pPixmap;
+ int x, y;
+
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+#ifdef COMPOSITE
+ x = -pPixmap->screen_x;
+ y = -pPixmap->screen_y;
+#else
+ x = 0;
+ y = 0;
+#endif
+ }
+ else
+ {
+ pPixmap = (PixmapPtr) pDrawable;
+ x = 0;
+ y = 0;
+ }
+ *xp = x;
+ *yp = y;
+ if (exaPixmapIsOffscreen (pPixmap))
+ return pPixmap;
+ else
+ return NULL;
+}
+
+Bool
+exaDrawableIsOffscreen (DrawablePtr pDrawable)
+{
+ PixmapPtr pPixmap;
+ STRACE;
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable);
+ else
+ pPixmap = (PixmapPtr) pDrawable;
+ return exaPixmapIsOffscreen (pPixmap);
+}
+
+#if 0
+static void
+exaFillTiled(int dst_x,
+ int dst_y,
+ int width,
+ int height,
+ int src_x,
+ int src_y,
+ int src_width,
+ int src_height,
+ void (*Copy) (int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height))
+{
+ modulus (src_x, src_width, src_x);
+ modulus (src_y, src_height, src_y);
+
+ while (height)
+ {
+ int dst_x_tmp = dst_x;
+ int src_x_tmp = src_x;
+ int width_tmp = width;
+ int height_left = src_height - src_y;
+ int height_this = min (height, height_left);
+
+ while (width_tmp)
+ {
+ int width_left = src_width - src_x_tmp;
+ int width_this = min (width_tmp, width_left);
+
+ (*Copy) (src_x_tmp, src_y,
+ dst_x_tmp, dst_y,
+ width_this, height_this);
+
+ width_tmp -= width_this;
+ dst_x_tmp += width_this;
+ }
+ height -= height_this;
+ dst_y += height_this;
+ src_y = 0;
+ }
+}
+#endif
+
+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;
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &off_x, &off_y)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (n--)
+ {
+ fullX1 = ppt->x;
+ fullY1 = ppt->y;
+ fullX2 = fullX1 + (int) *pwidth;
+ ppt++;
+ pwidth++;
+
+ if (fullY1 < extentY1 || extentY2 <= fullY1)
+ continue;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullX1 >= fullX2)
+ continue;
+
+ nbox = REGION_NUM_RECTS (pClip);
+ if (nbox == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + off_x, fullY1 + off_y,
+ fullX2 + off_x, fullY1 + 1 + off_y);
+ }
+ else
+ {
+ pbox = REGION_RECTS(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->accel.Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ pbox++;
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pScreen);
+}
+
+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);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ STRACE;
+
+ /* Migrate pixmaps to same place as destination */
+ if (pSrcDrawable->type == DRAWABLE_PIXMAP) {
+ if (exaDrawableIsOffscreen (pDstDrawable))
+ exaPixmapUseScreen ((PixmapPtr) pSrcDrawable);
+ else
+ exaPixmapUseMemory ((PixmapPtr) pSrcDrawable);
+ }
+
+ if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
+ (pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
+ (*pExaScr->info->accel.PrepareCopy) (pSrcPixmap,
+ pDstPixmap,
+ dx,
+ dy,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES))
+ {
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.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->accel.DoneCopy) (pDstPixmap);
+ exaMarkSync(pDstDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDstDrawable->pScreen);
+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC,
+ pbox, nbox, dx, dy, reverse, upsidedown,
+ bitplane, closure);
+ }
+ exaDrawableDirty (pDstDrawable);
+}
+
+static RegionPtr
+exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, exaCopyNtoN, 0, 0);
+}
+
+static void
+exaPolyFillRect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr 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;
+
+ STRACE;
+ if (pGC->fillStyle != FillSolid ||
+ !(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
+ return;
+ }
+
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, 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 = REGION_NUM_RECTS (pClip);
+ if (n == 1)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ fullX1 + xoff, fullY1 + yoff,
+ fullX2 + xoff, fullY2 + yoff);
+ }
+ else
+ {
+ pbox = REGION_RECTS(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect()
+ */
+ 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->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaSolidBoxClipped (DrawablePtr pDrawable,
+ RegionPtr pClip,
+ FbBits pm,
+ FbBits fg,
+ int x1,
+ int y1,
+ int x2,
+ int y2)
+{
+ ExaScreenPriv (pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int partX1, partX2, partY1, partY2;
+
+ STRACE;
+ if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) ||
+ !(*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, pm, fg))
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel);
+ fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2,
+ fbAnd (GXcopy, fg, pm),
+ fbXor (GXcopy, fg, pm));
+ exaDrawableDirty (pDrawable);
+ return;
+ }
+ for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < x1)
+ partX1 = x1;
+
+ partX2 = pbox->x2;
+ if (partX2 > x2)
+ partX2 = x2;
+
+ if (partX2 <= partX1)
+ continue;
+
+ partY1 = pbox->y1;
+ if (partY1 < y1)
+ partY1 = y1;
+
+ partY2 = pbox->y2;
+ if (partY2 > y2)
+ partY2 = y2;
+
+ if (partY2 <= partY1)
+ continue;
+
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaDrawableDirty (pDrawable);
+ exaMarkSync(pDrawable->pScreen);
+}
+
+static void
+exaImageGlyphBlt (DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nglyph,
+ CharInfoPtr *ppciInit,
+ pointer pglyphBase)
+{
+ FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
+ CharInfoPtr *ppci;
+ CharInfoPtr pci;
+ unsigned char *pglyph; /* pointer bits in glyph */
+ int gWidth, gHeight; /* width and height of glyph */
+ FbStride gStride; /* stride of glyph */
+ Bool opaque;
+ int n;
+ int gx, gy;
+ void (*glyph) (FbBits *,
+ FbStride,
+ int,
+ FbStip *,
+ FbBits,
+ int,
+ int);
+ FbBits *dst;
+ FbStride dstStride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+ FbBits depthMask;
+
+ STRACE;
+ depthMask = FbFullMask(pDrawable->depth);
+ if ((pGC->planemask & depthMask) != depthMask)
+ {
+ ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
+ return;
+ }
+ glyph = 0;
+ fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+ switch (dstBpp) {
+ case 8: glyph = fbGlyph8; break;
+ case 16: glyph = fbGlyph16; break;
+ case 24: glyph = fbGlyph24; break;
+ case 32: glyph = fbGlyph32; break;
+ }
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ if (TERMINALFONT (pGC->font) && !glyph)
+ {
+ opaque = TRUE;
+ }
+ else
+ {
+ int xBack, widthBack;
+ int yBack, heightBack;
+
+ ppci = ppciInit;
+ n = nglyph;
+ widthBack = 0;
+ while (n--)
+ widthBack += (*ppci++)->metrics.characterWidth;
+
+ xBack = x;
+ if (widthBack < 0)
+ {
+ xBack += widthBack;
+ widthBack = -widthBack;
+ }
+ yBack = y - FONTASCENT(pGC->font);
+ heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
+ exaSolidBoxClipped (pDrawable,
+ fbGetCompositeClip(pGC),
+ pGC->planemask,
+ pGC->bgPixel,
+ xBack,
+ yBack,
+ xBack + widthBack,
+ yBack + heightBack);
+ opaque = FALSE;
+ }
+
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+
+ ppci = ppciInit;
+ while (nglyph--)
+ {
+ pci = *ppci++;
+ pglyph = FONTGLYPHBITS(pglyphBase, pci);
+ gWidth = GLYPHWIDTHPIXELS(pci);
+ gHeight = GLYPHHEIGHTPIXELS(pci);
+ if (gWidth && gHeight)
+ {
+ gx = x + pci->metrics.leftSideBearing;
+ gy = y - pci->metrics.ascent;
+ if (glyph && gWidth <= sizeof (FbStip) * 8 &&
+ fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
+ {
+ (*glyph) (dst + (gy + dstYoff) * dstStride,
+ dstStride,
+ dstBpp,
+ (FbStip *) pglyph,
+ pPriv->fg,
+ gx + dstXoff,
+ gHeight);
+ }
+ else
+ {
+ gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
+ fbPutXYImage (pDrawable,
+ fbGetCompositeClip(pGC),
+ pPriv->fg,
+ pPriv->bg,
+ pPriv->pm,
+ GXcopy,
+ opaque,
+
+ gx,
+ gy,
+ gWidth, gHeight,
+
+ (FbStip *) pglyph,
+ gStride,
+ 0);
+ }
+ }
+ x += pci->metrics.characterWidth;
+ }
+}
+
+static const GCOps exaOps = {
+ exaFillSpans,
+ ExaCheckSetSpans,
+ ExaCheckPutImage,
+ exaCopyArea,
+ ExaCheckCopyPlane,
+ ExaCheckPolyPoint,
+ ExaCheckPolylines,
+ ExaCheckPolySegment,
+ miPolyRectangle,
+ ExaCheckPolyArc,
+ miFillPolygon,
+ exaPolyFillRect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ exaImageGlyphBlt,
+ ExaCheckPolyGlyphBlt,
+ ExaCheckPushPixels,
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};
+
+static void
+exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
+{
+ fbValidateGC (pGC, changes, pDrawable);
+
+ if (exaDrawableIsOffscreen (pDrawable))
+ pGC->ops = (GCOps *) &exaOps;
+ else
+ pGC->ops = (GCOps *) &exaAsyncPixmapGCOps;
+}
+
+GCFuncs exaGCFuncs = {
+ exaValidateGC,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+static int
+exaCreateGC (GCPtr pGC)
+{
+ STRACE;
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ pGC->funcs = &exaGCFuncs;
+
+ return TRUE;
+}
+
+
+static void
+exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+ STRACE;
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+#ifdef COMPOSITE
+ if (pPixmap->screen_x || pPixmap->screen_y)
+ REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+ fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ 0,
+ &rgnDst, dx, dy, exaCopyNtoN, 0, 0);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+static void
+exaFillRegionSolid (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ Pixel pixel)
+{
+ ExaScreenPriv(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ int xoff, yoff;
+
+ STRACE;
+ if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) &&
+ (*pExaScr->info->accel.PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel))
+ {
+ int nbox = REGION_NUM_RECTS (pRegion);
+ BoxPtr pBox = REGION_RECTS (pRegion);
+
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.Solid) (pPixmap,
+ pBox->x1 + xoff, pBox->y1 + yoff,
+ pBox->x2 + xoff, pBox->y2 + yoff);
+ pBox++;
+ }
+ (*pExaScr->info->accel.DoneSolid) (pPixmap);
+ exaMarkSync(pDrawable->pScreen);
+ }
+ else
+ {
+ exaWaitSync (pDrawable->pScreen);
+ fbFillRegionSolid (pDrawable, pRegion, 0,
+ fbReplicatePixel (pixel, pDrawable->bitsPerPixel));
+ }
+ exaDrawableDirty (pDrawable);
+}
+
+static void
+exaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ STRACE;
+ if (!REGION_NUM_RECTS(pRegion))
+ return;
+ switch (what) {
+ case PW_BACKGROUND:
+ switch (pWin->backgroundState) {
+ case None:
+ return;
+ case ParentRelative:
+ do {
+ pWin = pWin->parent;
+ } while (pWin->backgroundState == ParentRelative);
+ (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
+ what);
+ return;
+ case BackgroundPixel:
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->background.pixel);
+ return;
+#if 0
+ case BackgroundPixmap:
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->background.pixmap);
+ return;
+#endif
+ }
+ break;
+ case PW_BORDER:
+ if (pWin->borderIsPixel)
+ {
+ exaFillRegionSolid((DrawablePtr)pWin, pRegion, pWin->border.pixel);
+ return;
+ }
+#if 0
+ else
+ {
+ exaFillRegionTiled((DrawablePtr)pWin, pRegion, pWin->border.pixmap);
+ return;
+ }
+#endif
+ break;
+ }
+ ExaCheckPaintWindow (pWin, pRegion, what);
+}
+
+Bool
+exaDriverInit (ScreenPtr pScreen,
+ ExaDriverPtr pScreenInfo)
+{
+ ExaScreenPrivPtr pExaScr;
+
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+ STRACE;
+ if (exaGeneration != serverGeneration)
+ {
+ exaScreenPrivateIndex = AllocateScreenPrivateIndex();
+ exaPixmapPrivateIndex = AllocatePixmapPrivateIndex();
+ exaGeneration = serverGeneration;
+ }
+
+ pExaScr = xalloc (sizeof (ExaScreenPrivRec));
+
+ if (!pExaScr)
+ return FALSE;
+
+ pExaScr->info = pScreenInfo;
+
+ pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr;
+
+ /*
+ * Hook up asynchronous drawing
+ */
+ ExaScreenInitAsync (pScreen);
+ /*
+ * Replace various fb screen functions
+ */
+ pScreen->CreateGC = exaCreateGC;
+ pScreen->CopyWindow = exaCopyWindow;
+ pScreen->PaintWindowBackground = exaPaintWindow;
+ pScreen->PaintWindowBorder = exaPaintWindow;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = exaComposite;
+ }
+#endif
+
+ /*
+ * Hookup offscreen pixmaps
+ */
+ if ((pExaScr->info->card.flags & EXA_OFFSCREEN_PIXMAPS) &&
+ pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize)
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex,
+ sizeof (ExaPixmapPrivRec)))
+ return FALSE;
+ pScreen->CreatePixmap = exaCreatePixmap;
+ pScreen->DestroyPixmap = exaDestroyPixmap;
+ }
+ else
+ {
+ if (!AllocatePixmapPrivate(pScreen, exaPixmapPrivateIndex, 0))
+ return FALSE;
+ }
+
+ ErrorF("============== %ld < %ld\n", pExaScr->info->card.offScreenBase,
+ pExaScr->info->card.memorySize);
+ if (pExaScr->info->card.offScreenBase < pExaScr->info->card.memorySize) {
+ if (!exaOffscreenInit (pScreen))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+exaDriverFini (ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+
+ STRACE;
+ xfree (pExaScr);
+}
+
+
+void exaMarkSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ card->needsSync = TRUE;
+ if (pExaScr->info->accel.MarkSync != NULL) {
+ card->lastMarker = (*pExaScr->info->accel.MarkSync)(pScreen);
+ }
+}
+
+void exaWaitSync(ScreenPtr pScreen)
+{
+ ExaScreenPriv(pScreen);
+ ExaCardInfoPtr card = &(pExaScr->info->card);
+
+ if (card->needsSync) {
+ (*pExaScr->info->accel.WaitMarker)(pScreen, card->lastMarker);
+ card->needsSync = FALSE;
+ }
+}
+
+unsigned int exaGetVersion(void)
+{
+ return EXA_VERSION;
+}
+
+#ifdef XFree86LOADER
+static MODULESETUPPROTO(exaSetup);
+
+
+static const OptionInfoRec EXAOptions[] = {
+ { -1, NULL,
+ OPTV_NONE, {0}, FALSE }
+};
+
+/*ARGSUSED*/
+static const OptionInfoRec *
+EXAAvailableOptions(void *unused)
+{
+ return (EXAOptions);
+}
+
+static XF86ModuleVersionInfo exaVersRec =
+{
+ "exa",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 1, 2, 0,
+ ABI_CLASS_VIDEODRV, /* requires the video driver ABI */
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_NONE,
+ {0,0,0,0}
+};
+
+XF86ModuleData exaModuleData = { &exaVersRec, exaSetup, NULL };
+
+ModuleInfoRec EXA = {
+ 1,
+ "EXA",
+ NULL,
+ 0,
+ EXAAvailableOptions,
+};
+
+/*ARGSUSED*/
+static pointer
+exaSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
+{
+ static Bool Initialised = FALSE;
+
+ ErrorF("exa setup\n");
+ if (!Initialised) {
+ Initialised = TRUE;
+#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
+ if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
+#endif
+ xf86AddModuleInfo(&EXA, Module);
+ }
+
+ return (pointer)TRUE;
+}
+#endif
diff --git a/exa/exa_offscreen.c b/exa/exa_offscreen.c
new file mode 100644
index 000000000..def3fbdbb
--- /dev/null
+++ b/exa/exa_offscreen.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright © 2003 Anders Carlsson
+ *
+ * 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 Anders Carlsson not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Anders Carlsson makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL ANDERS CARLSSON 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.
+ */
+
+#include "exaPriv.h"
+
+#define DEBUG_OFFSCREEN 1
+#if DEBUG_OFFSCREEN
+#define DBG_OFFSCREEN(a) ErrorF a
+#else
+#define DBG_OFFSCREEN(a)
+#endif
+
+#if DEBUG_OFFSCREEN
+static void
+ExaOffscreenValidate (ScreenPtr pScreen)
+{
+ ExaScreenPriv (pScreen);
+ ExaOffscreenArea *prev = 0, *area;
+
+ assert (pExaScr->info->card.offScreenAreas->area.offset == 0);
+ for (area = pExaScr->info->card.offScreenAreas; area; area = area->next)
+ {
+ if (prev)
+ assert (prev->area.offset + prev->area.size == area->area.offset);
+
+ prev = area;
+ }
+ assert (prev->area.offset + prev->area.size == pExaScr->info->card.memorySize);
+}
+#else
+#define ExaOffscreenValidate(s)
+#endif
+
+static ExaOffscreenArea *
+ExaOffscreenKickOut (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ if (area->save)
+ (*area->save) (pScreen, area);
+ return exaOffscreenFree (pScreen, area);
+}
+
+ExaOffscreenArea *
+exaOffscreenAlloc (ScreenPtr pScreen, int size, int align,
+ Bool locked,
+ ExaOffscreenSaveProc save,
+ pointer privData)
+{
+ ExaOffscreenArea *area, *begin, *best;
+ ExaScreenPriv (pScreen);
+ int tmp, real_size = 0, best_score;
+#if DEBUG_OFFSCREEN
+ static int number = 0;
+ ErrorF("================= ============ allocating a new pixmap %d\n", ++number);
+#endif
+
+ ExaOffscreenValidate (pScreen);
+ if (!align)
+ align = 1;
+
+ if (!size)
+ {
+ DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size));
+ return NULL;
+ }
+
+ /* throw out requests that cannot fit */
+ if (size > (pExaScr->info->card.memorySize - pExaScr->info->card.offScreenBase))
+ {
+ DBG_OFFSCREEN (("Alloc 0x%x -> TOBIG\n", size));
+ return NULL;
+ }
+
+ /* Try to find a free space that'll fit. */
+ for (area = pExaScr->info->card.offScreenAreas; area; area = area->next)
+ {
+ /* skip allocated areas */
+ if (area->state != ExaOffscreenAvail)
+ continue;
+
+ /* adjust size to match alignment requirement */
+ real_size = size;
+ tmp = area->offset % align;
+ if (tmp)
+ real_size += (align - tmp);
+
+ /* does it fit? */
+ if (real_size <= area->size)
+ break;
+ }
+
+ if (!area)
+ {
+ /*
+ * Kick out existing users to make space.
+ *
+ * First, locate a region which can hold the desired object.
+ */
+
+ /* prev points at the first object to boot */
+ best = NULL;
+ best_score = MAXINT;
+ for (begin = pExaScr->info->card.offScreenAreas; begin != NULL;
+ begin = begin->next)
+ {
+ int avail, score;
+ ExaOffscreenArea *scan;
+
+ if (begin->state == ExaOffscreenLocked)
+ continue;
+
+ /* adjust size to match alignment requirement */
+ real_size = size;
+ tmp = begin->offset % align;
+ if (tmp)
+ real_size += (align - tmp);
+
+ avail = 0;
+ score = 0;
+ /* now see if we can make room here, and how "costly" it'll be. */
+ for (scan = begin; scan != NULL; scan = scan->next)
+ {
+ if (scan->state == ExaOffscreenLocked) {
+ /* Can't make room here, start after this locked area. */
+ begin = scan->next;
+ break;
+ }
+ /* Score should only be non-zero for ExaOffscreenRemovable */
+ score += scan->score;
+ avail += scan->size;
+ if (avail >= real_size)
+ break;
+ }
+ /* Is it the best option we've found so far? */
+ if (avail >= real_size && score < best_score) {
+ best = begin;
+ best_score = score;
+ }
+ }
+ area = best;
+ if (!area)
+ {
+ DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size));
+ /* Could not allocate memory */
+ ExaOffscreenValidate (pScreen);
+ return NULL;
+ }
+
+ /* adjust size to match alignment requirement */
+ real_size = size;
+ tmp = begin->offset % align;
+ if (tmp)
+ real_size += (align - tmp);
+
+ /*
+ * Kick out first area if in use
+ */
+ if (area->state != ExaOffscreenAvail)
+ area = ExaOffscreenKickOut (pScreen, area);
+ /*
+ * Now get the system to merge the other needed areas together
+ */
+ while (area->size < real_size)
+ {
+ assert (area->next && area->next->state == ExaOffscreenRemovable);
+ (void) ExaOffscreenKickOut (pScreen, area->next);
+ }
+ }
+
+ /* save extra space in new area */
+ if (real_size < area->size)
+ {
+ ExaOffscreenArea *new_area = xalloc (sizeof (ExaOffscreenArea));
+ if (!new_area)
+ return NULL;
+ new_area->offset = area->offset + real_size;
+ new_area->size = area->size - real_size;
+ new_area->state = ExaOffscreenAvail;
+ new_area->save = 0;
+ new_area->score = 0;
+ new_area->next = area->next;
+ area->next = new_area;
+ area->size = real_size;
+ }
+ /*
+ * Mark this area as in use
+ */
+ if (locked)
+ area->state = ExaOffscreenLocked;
+ else
+ area->state = ExaOffscreenRemovable;
+ area->privData = privData;
+ area->save = save;
+ area->score = 0;
+
+ area->save_offset = area->offset;
+ area->offset = (area->offset + align - 1) & ~(align - 1);
+
+ ExaOffscreenValidate (pScreen);
+
+ DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x\n", size, area->offset));
+ return area;
+}
+
+void
+ExaOffscreenSwapOut (ScreenPtr pScreen)
+{
+ ExaScreenPriv (pScreen);
+
+ ExaOffscreenValidate (pScreen);
+ /* loop until a single free area spans the space */
+ for (;;)
+ {
+ ExaOffscreenArea *area = pExaScr->info->card.offScreenAreas;
+
+ if (!area)
+ break;
+ if (area->state == ExaOffscreenAvail)
+ {
+ area = area->next;
+ if (!area)
+ break;
+ }
+ assert (area->state != ExaOffscreenAvail);
+ (void) ExaOffscreenKickOut (pScreen, area);
+ ExaOffscreenValidate (pScreen);
+ }
+ ExaOffscreenValidate (pScreen);
+ ExaOffscreenFini (pScreen);
+}
+
+void
+ExaOffscreenSwapIn (ScreenPtr pScreen)
+{
+ exaOffscreenInit (pScreen);
+}
+
+/* merge the next free area into this one */
+static void
+ExaOffscreenMerge (ExaOffscreenArea *area)
+{
+ ExaOffscreenArea *next = area->next;
+
+ /* account for space */
+ area->size += next->size;
+ /* frob pointer */
+ area->next = next->next;
+ xfree (next);
+}
+
+ExaOffscreenArea *
+exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ ExaScreenPriv(pScreen);
+ ExaOffscreenArea *next = area->next;
+ ExaOffscreenArea *prev;
+
+ DBG_OFFSCREEN (("Free 0x%x -> 0x%x\n", area->size, area->offset));
+ ExaOffscreenValidate (pScreen);
+
+ area->state = ExaOffscreenAvail;
+ area->save = 0;
+ area->offset = area->save_offset;
+ area->score = 0;
+ /*
+ * Find previous area
+ */
+ if (area == pExaScr->info->card.offScreenAreas)
+ prev = 0;
+ else
+ for (prev = pExaScr->info->card.offScreenAreas; prev; prev = prev->next)
+ if (prev->next == area)
+ break;
+
+ /* link with next area if free */
+ if (next && next->state == ExaOffscreenAvail)
+ ExaOffscreenMerge (area);
+
+ /* link with prev area if free */
+ if (prev && prev->state == ExaOffscreenAvail)
+ {
+ area = prev;
+ ExaOffscreenMerge (area);
+ }
+
+ ExaOffscreenValidate (pScreen);
+ DBG_OFFSCREEN(("\tdone freeing\n"));
+ return area;
+}
+
+void
+ExaOffscreenMarkUsed (PixmapPtr pPixmap)
+{
+ ExaPixmapPriv (pPixmap);
+ ExaScreenPriv (pPixmap->drawable.pScreen);
+ static int iter = 0;
+
+ if (!pExaPixmap->area)
+ return;
+
+ /* The numbers here are arbitrary. We may want to tune these. */
+ pExaPixmap->area->score += 100;
+ if (++iter == 10) {
+ ExaOffscreenArea *area;
+ for (area = pExaScr->info->card.offScreenAreas; area != NULL;
+ area = area->next)
+ {
+ if (area->state == ExaOffscreenRemovable)
+ area->score = (area->score * 7) / 8;
+ }
+ }
+}
+
+Bool
+exaOffscreenInit (ScreenPtr pScreen)
+{
+ ExaScreenPriv (pScreen);
+ ExaOffscreenArea *area;
+
+ /* Allocate a big free area */
+ area = xalloc (sizeof (ExaOffscreenArea));
+
+ if (!area)
+ return FALSE;
+
+
+ area->state = ExaOffscreenAvail;
+ area->offset = pExaScr->info->card.offScreenBase;
+ area->size = pExaScr->info->card.memorySize - area->offset;
+ area->save = 0;
+ area->next = NULL;
+ area->score = 0;
+
+ ErrorF("============ initial memory block of %d\n", area->size);
+
+ /* Add it to the free areas */
+ pExaScr->info->card.offScreenAreas = area;
+
+ ExaOffscreenValidate (pScreen);
+
+ return TRUE;
+}
+
+void
+ExaOffscreenFini (ScreenPtr pScreen)
+{
+ ExaScreenPriv (pScreen);
+ ExaOffscreenArea *area;
+
+ /* just free all of the area records */
+ while ((area = pExaScr->info->card.offScreenAreas))
+ {
+ pExaScr->info->card.offScreenAreas = area->next;
+ xfree (area);
+ }
+}
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
new file mode 100644
index 000000000..546a538cc
--- /dev/null
+++ b/exa/exa_priv.h
@@ -0,0 +1,281 @@
+/*
+ *
+ * Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * 2005 Zack Rusin, Trolltech
+ *
+ * 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.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ */
+
+#ifndef EXAPRIV_H
+#define EXAPRIV_H
+
+#include "exa.h"
+
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "dix.h"
+#include "fb.h"
+#include "fboverlay.h"
+
+#ifndef EXA_MAX_FB
+#define EXA_MAX_FB FB_OVERLAY_MAX
+#endif
+
+
+/*
+ * This is the only completely portable way to
+ * compute this info.
+ */
+#ifndef BitsPerPixel
+#define BitsPerPixel(d) (\
+ PixmapWidthPaddingInfo[d].notPower2 ? \
+ (PixmapWidthPaddingInfo[d].bytesPerPixel * 8) : \
+ ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \
+ (PixmapWidthPaddingInfo[d].padRoundUp+1)))
+#endif
+
+extern int exaScreenPrivateIndex;
+extern int exaPixmapPrivateIndex;
+#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)(s)->devPrivates[exaScreenPrivateIndex].ptr)
+#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
+
+#define ExaGetPixmapPriv(p) ((ExaPixmapPrivPtr)(p)->devPrivates[exaPixmapPrivateIndex].ptr)
+#define ExaSetPixmapPriv(p,a) ((p)->devPrivates[exaPixmapPrivateIndex].ptr = (pointer) (a))
+#define ExaPixmapPriv(p) ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv(p)
+
+typedef struct {
+ ExaOffscreenArea *area;
+ int score;
+ int devKind;
+ DevUnion devPrivate;
+ Bool dirty;
+} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
+
+
+/* exaasync.c */
+void
+ExaCheckFillSpans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted);
+
+void
+ExaCheckSetSpans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
+
+void
+ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits);
+
+RegionPtr
+ExaCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty);
+
+RegionPtr
+ExaCheckCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane);
+
+void
+ExaCheckPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit);
+
+void
+ExaCheckPolylines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt);
+
+void
+ExaCheckPolySegment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit);
+
+void
+ExaCheckPolyRectangle (DrawablePtr pDrawable, GCPtr pGC,
+ int nrects, xRectangle *prect);
+
+void
+ExaCheckPolyArc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs);
+
+#define ExaCheckFillPolygon miFillPolygon
+
+void
+ExaCheckPolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect);
+
+void
+ExaCheckPolyFillArc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs);
+
+void
+ExaCheckImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+ExaCheckPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+ExaCheckPushPixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y);
+
+void
+ExaCheckGetImage (DrawablePtr pDrawable,
+ int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask,
+ char *d);
+
+void
+ExaCheckGetSpans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart);
+
+void
+ExaCheckSaveAreas (PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin);
+
+void
+ExaCheckRestoreAreas (PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin);
+
+void
+ExaCheckPaintWindow (WindowPtr pWin, RegionPtr pRegion, int what);
+
+void
+ExaCheckCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
+
+void
+ExaCheckPaintKey(DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ CARD32 pixel,
+ int layer);
+
+void
+ExaCheckOverlayCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
+
+void
+ExaScreenInitAsync (ScreenPtr pScreen);
+
+extern const GCOps exaAsyncPixmapGCOps;
+
+/* exapict.c */
+void
+ExaPictureInitAsync (ScreenPtr pScreen);
+
+#ifdef RENDER
+void
+ExaCheckComposite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+#endif
+
+/* exaoffscreen.c */
+void
+ExaOffscreenMarkUsed (PixmapPtr pPixmap);
+
+void
+ExaOffscreenSwapOut (ScreenPtr pScreen);
+
+void
+ExaOffscreenSwapIn (ScreenPtr pScreen);
+
+void
+ExaOffscreenFini (ScreenPtr pScreen);
+
+/* exa.c */
+void
+exaPixmapUseScreen (PixmapPtr pPixmap);
+
+void
+exaPixmapUseMemory (PixmapPtr pPixmap);
+
+void
+exaDrawableDirty(DrawablePtr pDrawable);
+
+Bool
+exaDrawableIsOffscreen (DrawablePtr pDrawable);
+
+Bool
+exaPixmapIsOffscreen(PixmapPtr p);
+
+PixmapPtr
+exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp);
+
+void
+exaMoveInPixmap (PixmapPtr pPixmap);
+
+void
+exaCopyNtoN (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure);
+
+void
+exaComposite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+
+#endif /* EXAPRIV_H */
diff --git a/exa/exa_render.c b/exa/exa_render.c
new file mode 100644
index 000000000..b48e9c701
--- /dev/null
+++ b/exa/exa_render.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "exaPriv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+
+#define EXA_DEBUG_FALLBACKS 0
+
+#if EXA_DEBUG_FALLBACKS
+static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
+{
+ char format[20];
+ char size[20];
+ char loc;
+ int temp;
+
+ if (!pict) {
+ snprintf(string, n, "None");
+ return;
+ }
+
+ switch (pict->format)
+ {
+ case PICT_a8r8g8b8:
+ snprintf(format, 20, "ARGB8888");
+ break;
+ case PICT_r5g6b5:
+ snprintf(format, 20, "RGB565 ");
+ break;
+ case PICT_x1r5g5b5:
+ snprintf(format, 20, "RGB555 ");
+ break;
+ case PICT_a8:
+ snprintf(format, 20, "A8 ");
+ break;
+ case PICT_a1:
+ snprintf(format, 20, "A1 ");
+ break;
+ default:
+ snprintf(format, 20, "0x%x", (int)pict->format);
+ break;
+ }
+
+ loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
+
+ snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
+ pict->pDrawable->height, pict->repeat ?
+ " R" : "");
+
+ snprintf(string, n, "0x%lx:%c fmt %s (%s)", (long)pict, loc, format, size);
+}
+
+static void
+exaPrintCompositeFallback(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst)
+{
+ char sop[20];
+ char srcdesc[40], maskdesc[40], dstdesc[40];
+
+ switch(op)
+ {
+ case PictOpSrc:
+ sprintf(sop, "Src");
+ break;
+ case PictOpOver:
+ sprintf(sop, "Over");
+ break;
+ default:
+ sprintf(sop, "0x%x", (int)op);
+ break;
+ }
+
+ exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
+ exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
+ exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
+
+ ErrorF("Composite fallback: op %s, \n"
+ " src %s, \n"
+ " mask %s, \n"
+ " dst %s, \n",
+ sop, srcdesc, maskdesc, dstdesc);
+}
+#endif
+
+static Bool
+exaGetPixelFromRGBA(CARD32 *pixel,
+ CARD16 red,
+ CARD16 green,
+ CARD16 blue,
+ CARD16 alpha,
+ CARD32 format)
+{
+ int rbits, bbits, gbits, abits;
+ int rshift, bshift, gshift, ashift;
+
+ *pixel = 0;
+
+ if (!PICT_FORMAT_COLOR(format))
+ return FALSE;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else { /* PICT_TYPE_ABGR */
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ }
+
+ *pixel |= ( blue >> (16 - bbits)) << bshift;
+ *pixel |= ( red >> (16 - rbits)) << rshift;
+ *pixel |= (green >> (16 - gbits)) << gshift;
+ *pixel |= (alpha >> (16 - abits)) << ashift;
+
+ return TRUE;
+}
+
+
+static Bool
+exaGetRGBAFromPixel(CARD32 pixel,
+ CARD16 *red,
+ CARD16 *green,
+ CARD16 *blue,
+ CARD16 *alpha,
+ CARD32 format)
+{
+ int rbits, bbits, gbits, abits;
+ int rshift, bshift, gshift, ashift;
+
+ if (!PICT_FORMAT_COLOR(format))
+ return FALSE;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else { /* PICT_TYPE_ABGR */
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ }
+
+ *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
+ while (rbits < 16) {
+ *red |= *red >> rbits;
+ rbits <<= 1;
+ }
+
+ *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
+ while (gbits < 16) {
+ *green |= *green >> gbits;
+ gbits <<= 1;
+ }
+
+ *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
+ while (bbits < 16) {
+ *blue |= *blue >> bbits;
+ bbits <<= 1;
+ }
+
+ if (abits) {
+ *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
+ while (abits < 16) {
+ *alpha |= *alpha >> abits;
+ abits <<= 1;
+ }
+ } else
+ *alpha = 0xffff;
+
+ return TRUE;
+}
+
+static int
+exaTryDriverSolidFill(PicturePtr pSrc,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ ExaScreenPriv (pDst->pDrawable->pScreen);
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+ int dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pDstPix;
+ CARD32 pixel;
+ CARD16 red, green, blue, alpha;
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ width, height))
+ return 1;
+
+ if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable);
+ if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseScreen ((PixmapPtr) pDst->pDrawable);
+
+ pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
+ if (!pDstPix) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
+ pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap)(
+ (WindowPtr) (pSrc->pDrawable));
+ else
+ pSrcPix = (PixmapPtr) (pSrc->pDrawable);
+
+ /* If source is offscreen, we need to sync the accelerator
+ * before accessing it. We'd prefer for it to be in memory.
+ */
+ if (exaPixmapIsOffscreen(pSrcPix)) {
+ exaWaitSync(pDst->pDrawable->pScreen);
+ }
+
+ pixel = *(CARD32 *)(pSrcPix->devPrivate.ptr);
+ if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
+ pSrc->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+ exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
+ pDst->format);
+
+ if (!(*pExaScr->info->accel.PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.Solid) (pDstPix,
+ pbox->x1 + dst_off_x,
+ pbox->y1 + dst_off_y,
+ pbox->x2 + dst_off_x,
+ pbox->y2 + dst_off_y);
+ pbox++;
+ }
+
+ (*pExaScr->info->accel.DoneSolid) (pDstPix);
+ exaMarkSync(pDst->pDrawable->pScreen);
+ exaDrawableDirty (pDst->pDrawable);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+static int
+exaTryDriverComposite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ ExaScreenPriv (pDst->pDrawable->pScreen);
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+ int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
+ struct _Pixmap scratch;
+
+ if (pExaScr->info->card.maxX < width ||
+ pExaScr->info->card.maxY < height)
+ {
+ int total_width = width;
+ int total_height = height;
+ int xOff = 0;
+ int yOff = 0;
+ while (total_width > pExaScr->info->card.maxX) {
+ while (total_height > pExaScr->info->card.maxY) {
+ exaTryDriverComposite(op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc + xOff,
+ ySrc + yOff,
+ xMask + xOff,
+ yMask + yOff,
+ xDst + xOff,
+ yDst + yOff,
+ pExaScr->info->card.maxX,
+ pExaScr->info->card.maxY);
+ total_width -= pExaScr->info->card.maxX;
+ xOff += pExaScr->info->card.maxX;
+ yOff = 0;
+ }
+ if (total_height)
+ exaTryDriverComposite(op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc + xOff,
+ ySrc + yOff,
+ xMask + xOff,
+ yMask + yOff,
+ xDst + xOff,
+ yDst + yOff,
+ pExaScr->info->card.maxX,
+ total_height);
+ total_height -= pExaScr->info->card.maxY;
+ yOff += pExaScr->info->card.maxY;
+ }
+ if (total_width && total_height)
+ exaTryDriverComposite(op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc + xOff,
+ ySrc + yOff,
+ xMask + xOff,
+ yMask + yOff,
+ xDst + xOff,
+ yDst + yOff,
+ total_width,
+ total_height);
+
+ return -1;
+ }
+
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+
+ if (pMask) {
+ xMask += pMask->pDrawable->x;
+ yMask += pMask->pDrawable->y;
+ }
+
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ return 1;
+
+ if (pExaScr->info->accel.CheckComposite &&
+ !(*pExaScr->info->accel.CheckComposite) (op, pSrc, pMask, pDst))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseScreen ((PixmapPtr) pSrc->pDrawable);
+ if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseScreen ((PixmapPtr) pMask->pDrawable);
+ if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseScreen ((PixmapPtr) pDst->pDrawable);
+
+ pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (pMask)
+ pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
+ &mask_off_y);
+ pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
+
+ if (!pDstPix) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->accel.UploadToScratch) {
+ if (pSrc->pDrawable->type == DRAWABLE_WINDOW)
+ pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap) (
+ (WindowPtr) pSrc->pDrawable);
+ else
+ pSrcPix = (PixmapPtr) pSrc->pDrawable;
+ if ((*pExaScr->info->accel.UploadToScratch) (pSrcPix, &scratch))
+ pSrcPix = &scratch;
+ } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->accel.UploadToScratch) {
+ if (pMask->pDrawable->type == DRAWABLE_WINDOW)
+ pMaskPix = (*pMask->pDrawable->pScreen->GetWindowPixmap) (
+ (WindowPtr) pMask->pDrawable);
+ else
+ pMaskPix = (PixmapPtr) pMask->pDrawable;
+ if ((*pExaScr->info->accel.UploadToScratch) (pMaskPix, &scratch))
+ pMaskPix = &scratch;
+ }
+
+ if (!pSrcPix || (pMask && !pMaskPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!(*pExaScr->info->accel.PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
+ pMaskPix, pDstPix))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ xMask -= xDst;
+ yMask -= yDst;
+
+ xSrc -= xDst;
+ ySrc -= yDst;
+
+ while (nbox--)
+ {
+ (*pExaScr->info->accel.Composite) (pDstPix,
+ pbox->x1 + xSrc + src_off_x,
+ pbox->y1 + ySrc + src_off_y,
+ pbox->x1 + xMask + mask_off_x,
+ pbox->y1 + yMask + mask_off_y,
+ pbox->x1 + dst_off_x,
+ pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ (*pExaScr->info->accel.DoneComposite) (pDstPix);
+ exaMarkSync(pDst->pDrawable->pScreen);
+ exaDrawableDirty (pDst->pDrawable);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+
+void
+exaComposite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ ExaScreenPriv (pDst->pDrawable->pScreen);
+ int ret = -1;
+
+ if (!pMask && pSrc->pDrawable)
+ {
+ if (op == PictOpSrc)
+ {
+ if (pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 && pSrc->repeat)
+ {
+ ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ return;
+ }
+ else if (!pSrc->repeat && !pSrc->transform &&
+ pSrc->format == pDst->format)
+ {
+ RegionRec region;
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst,
+ yDst, width, height))
+ return;
+
+
+ exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, 0,
+ REGION_RECTS(&region), REGION_NUM_RECTS(&region),
+ xSrc - xDst, ySrc - yDst,
+ FALSE, FALSE, 0, 0);
+ return;
+ }
+ }
+ }
+
+ if (pSrc->pDrawable && (!pMask || pMask->pDrawable) &&
+ pExaScr->info->accel.PrepareComposite &&
+ !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
+ {
+ ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
+ yMask, xDst, yDst, width, height);
+ if (ret == 1)
+ return;
+ }
+
+ if (ret != 0) {
+ /* failure to accelerate was not due to pixmaps being in the wrong
+ * locations.
+ */
+ if (pSrc->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable);
+ if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseMemory ((PixmapPtr) pMask->pDrawable);
+ if (pDst->pDrawable->type == DRAWABLE_PIXMAP)
+ exaPixmapUseMemory ((PixmapPtr) pDst->pDrawable);
+ }
+
+#if EXA_DEBUG_FALLBACKS
+ exaPrintCompositeFallback (op, pSrc, pMask, pDst);
+#endif
+
+ ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
+ xMask, yMask, xDst, yDst, width, height);
+}
+#endif
diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
new file mode 100644
index 000000000..79c407417
--- /dev/null
+++ b/exa/exa_unaccel.c
@@ -0,0 +1,365 @@
+/*
+ *
+ * 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
+ * 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.
+ */
+
+#include "exaPriv.h"
+
+/*
+ * These functions wrap the low-level fb rendering functions and
+ * synchronize framebuffer/accelerated drawing by stalling until
+ * the accelerator is idle
+ */
+
+void
+ExaCheckFillSpans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted);
+}
+
+void
+ExaCheckSetSpans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+}
+
+void
+ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits)
+{
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
+}
+
+RegionPtr
+ExaCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+ exaWaitSync (pSrc->pScreen);
+ exaDrawableDirty (pDst);
+ return fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+}
+
+RegionPtr
+ExaCheckCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane)
+{
+ exaWaitSync (pSrc->pScreen);
+ exaDrawableDirty (pDst);
+ return fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
+ bitPlane);
+}
+
+void
+ExaCheckPolyPoint (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit)
+{
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPolyPoint (pDrawable, pGC, mode, npt, pptInit);
+}
+
+void
+ExaCheckPolylines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt)
+{
+
+ if (pGC->lineWidth == 0) {
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ }
+ exaDrawableDirty (pDrawable);
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+}
+
+void
+ExaCheckPolySegment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit)
+{
+ if (pGC->lineWidth == 0) {
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ }
+ exaDrawableDirty (pDrawable);
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+}
+
+void
+ExaCheckPolyRectangle (DrawablePtr pDrawable, GCPtr pGC,
+ int nrects, xRectangle *prect)
+{
+ if (pGC->lineWidth == 0) {
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ }
+ fbPolyRectangle (pDrawable, pGC, nrects, prect);
+}
+
+void
+ExaCheckPolyArc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs)
+{
+ if (pGC->lineWidth == 0)
+ {
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPolyArc (pDrawable, pGC, narcs, pArcs);
+ }
+ else
+ miPolyArc (pDrawable, pGC, narcs, pArcs);
+}
+
+#if 0
+void
+ExaCheckFillPolygon (DrawablePtr pDrawable, GCPtr pGC,
+ int shape, int mode, int count, DDXPointPtr pPts)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbFillPolygon (pDrawable, pGC, mode, count, pPts);
+}
+#endif
+
+void
+ExaCheckPolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPolyFillRect (pDrawable, pGC, nrect, prect);
+}
+
+void
+ExaCheckPolyFillArc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPolyFillArc (pDrawable, pGC, narcs, pArcs);
+}
+
+void
+ExaCheckImageGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+}
+
+void
+ExaCheckPolyGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+}
+
+void
+ExaCheckPushPixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y)
+{
+ exaWaitSync(pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y);
+}
+
+void
+ExaCheckGetImage (DrawablePtr pDrawable,
+ int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask,
+ char *d)
+{
+ exaWaitSync(pDrawable->pScreen);
+ fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+}
+
+void
+ExaCheckGetSpans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart)
+{
+ exaWaitSync(pDrawable->pScreen);
+ fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+}
+
+void
+ExaCheckSaveAreas (PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin)
+{
+ exaWaitSync(pWin->drawable.pScreen);
+ exaDrawableDirty (&pPixmap->drawable);
+ fbSaveAreas (pPixmap, prgnSave, xorg, yorg, pWin);
+}
+
+void
+ExaCheckRestoreAreas (PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin)
+{
+ exaWaitSync(pWin->drawable.pScreen);
+ exaDrawableDirty ((DrawablePtr)pWin);
+ fbRestoreAreas (pPixmap, prgnSave, xorg, yorg, pWin);
+}
+
+void
+ExaCheckPaintWindow (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ exaWaitSync (pWin->drawable.pScreen);
+ exaDrawableDirty ((DrawablePtr)pWin);
+ fbPaintWindow (pWin, pRegion, what);
+}
+
+void
+ExaCheckCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ exaWaitSync (pWin->drawable.pScreen);
+ exaDrawableDirty ((DrawablePtr)pWin);
+ fbCopyWindow (pWin, ptOldOrg, prgnSrc);
+}
+
+#if EXA_MAX_FB > 1
+void
+ExaCheckPaintKey(DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ CARD32 pixel,
+ int layer)
+{
+ exaWaitSync (pDrawable->pScreen);
+ exaDrawableDirty (pDrawable);
+ fbOverlayPaintKey (pDrawable, pRegion, pixel, layer);
+}
+
+void
+ExaCheckOverlayCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ exaWaitSync (pWin->drawable.pScreen);
+ exaDrawableDirty ((DrawablePtr)pWin);
+ fbOverlayCopyWindow (pWin, ptOldOrg, prgnSrc);
+}
+#endif
+
+void
+ExaScreenInitAsync (ScreenPtr pScreen)
+{
+ pScreen->GetImage = ExaCheckGetImage;
+ pScreen->GetSpans = ExaCheckGetSpans;
+ pScreen->PaintWindowBackground = ExaCheckPaintWindow;
+ pScreen->PaintWindowBorder = ExaCheckPaintWindow;
+ pScreen->CopyWindow = ExaCheckCopyWindow;
+ pScreen->BackingStoreFuncs.SaveAreas = ExaCheckSaveAreas;
+ pScreen->BackingStoreFuncs.RestoreAreas = ExaCheckRestoreAreas;
+
+#ifdef RENDER
+ ExaPictureInitAsync (pScreen);
+#endif
+}
+
+
+void
+ExaCheckComposite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ exaWaitSync (pDst->pDrawable->pScreen);
+ exaDrawableDirty (pDst->pDrawable);
+ fbComposite (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc,
+ ySrc,
+ xMask,
+ yMask,
+ xDst,
+ yDst,
+ width,
+ height);
+}
+
+void
+ExaPictureInitAsync (ScreenPtr pScreen)
+{
+ PictureScreenPtr ps;
+
+ ps = GetPictureScreen(pScreen);
+ ps->Composite = ExaCheckComposite;
+}
+
+
+/*
+ * Only need to stall for copyarea/copyplane
+ */
+const GCOps exaAsyncPixmapGCOps = {
+ fbFillSpans,
+ fbSetSpans,
+ fbPutImage,
+ ExaCheckCopyArea,
+ ExaCheckCopyPlane,
+ fbPolyPoint,
+ fbPolyLine,
+ fbPolySegment,
+ fbPolyRectangle,
+ fbPolyArc,
+ fbFillPolygon,
+ fbPolyFillRect,
+ fbPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ fbImageGlyphBlt,
+ fbPolyGlyphBlt,
+ fbPushPixels
+#ifdef NEED_LINEHELPER
+ ,NULL
+#endif
+};