summaryrefslogtreecommitdiff
path: root/uxa
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-07-29 22:57:09 -0700
committerKeith Packard <keithp@keithp.com>2008-08-05 15:29:50 -0700
commit59774e9aca2d743e82d616bb644d20ff6d60d492 (patch)
tree209dfbdbfa8eb9dbd9cfc7a41be3fa3a7ead19ac /uxa
parentc2f0df4dc97c87539b66525a277c7d1e2c421f61 (diff)
Add UXA - the unified memory acceleration architecture.
This eliminates the cost of EXA migration management while providing full pixmap allocation control to the driver. The goal is to make something useful for UMA drivers.
Diffstat (limited to 'uxa')
-rw-r--r--uxa/Makefile.am20
-rw-r--r--uxa/uxa-accel.c1038
-rw-r--r--uxa/uxa-glyphs.c880
-rw-r--r--uxa/uxa-priv.h444
-rw-r--r--uxa/uxa-render.c1052
-rw-r--r--uxa/uxa-unaccel.c370
-rw-r--r--uxa/uxa.c573
-rw-r--r--uxa/uxa.h671
8 files changed, 5048 insertions, 0 deletions
diff --git a/uxa/Makefile.am b/uxa/Makefile.am
new file mode 100644
index 00000000..641b4146
--- /dev/null
+++ b/uxa/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libuxa.la
+
+# Override these since UXA doesn't need them and the needed files aren't
+# built (in hw/xfree86/os-support/solaris) until after UXA is built
+SOLARIS_ASM_CFLAGS=""
+
+INCLUDES = \
+ $(XORG_INCS)
+
+AM_CFLAGS = $(WARN_CFLAGS) $(XORG_CFLAGS) $(DIX_CFLAGS)
+
+libuxa_la_SOURCES = \
+ uxa.c \
+ uxa.h \
+ uxa-accel.c \
+ uxa-glyphs.c \
+ uxa-render.c \
+ uxa-priv.h \
+ uxa-unaccel.c
+
diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c
new file mode 100644
index 00000000..7c7b3e9b
--- /dev/null
+++ b/uxa/uxa-accel.c
@@ -0,0 +1,1038 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Michel Dänzer <michel@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "uxa.h"
+
+static void
+uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid ||
+ !(pPixmap = uxa_get_offscreen_pixmap (pDrawable, &off_x, &off_y)) ||
+ !(*uxa_screen->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ uxa_check_fill_spans (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)
+ {
+ (*uxa_screen->info->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) {
+ (*uxa_screen->info->Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ }
+ pbox++;
+ }
+ }
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pScreen);
+}
+
+static Bool
+uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int format, char *bits, int src_stride)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable);
+ RegionPtr pClip;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int bpp = pDrawable->bitsPerPixel;
+ Bool access_prepared = FALSE;
+
+ /* Don't bother with under 8bpp, XYPixmaps. */
+ if (format != ZPixmap || bpp < 8)
+ return FALSE;
+
+ /* Only accelerate copies: no rop or planemask. */
+ if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
+ return FALSE;
+
+ if (uxa_screen->swappedOut)
+ return FALSE;
+
+ pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPix || !uxa_screen->info->UploadToScreen)
+ return FALSE;
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ pClip = fbGetCompositeClip(pGC);
+ for (nbox = REGION_NUM_RECTS(pClip),
+ pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+ char *src;
+ Bool ok;
+
+ if (x1 < pbox->x1)
+ x1 = pbox->x1;
+ if (y1 < pbox->y1)
+ y1 = pbox->y1;
+ if (x2 > pbox->x2)
+ x2 = pbox->x2;
+ if (y2 > pbox->y2)
+ y2 = pbox->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
+ ok = uxa_screen->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
+ x2 - x1, y2 - y1, src, src_stride);
+ /* If we fail to accelerate the upload, fall back to using unaccelerated
+ * fb calls.
+ */
+ if (!ok) {
+ FbStip *dst;
+ FbStride dst_stride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+
+ if (!access_prepared) {
+ uxa_prepare_access(pDrawable, UXA_PREPARE_DEST);
+
+ access_prepared = TRUE;
+ }
+
+ fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
+ dstXoff, dstYoff);
+
+ fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
+ src_stride / sizeof(FbStip),
+ (x1 - x) * dstBpp,
+ dst + (y1 + dstYoff) * dst_stride,
+ dst_stride,
+ (x1 + dstXoff) * dstBpp,
+ (x2 - x1) * dstBpp,
+ y2 - y1,
+ GXcopy, FB_ALLONES, dstBpp);
+ }
+ }
+
+ if (access_prepared)
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+ else
+ uxa_mark_sync(pDrawable->pScreen);
+
+ return TRUE;
+}
+
+#ifdef MITSHM
+
+static Bool
+uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
+ unsigned int format, int w, int h, int sx, int sy, int sw,
+ int sh, int dx, int dy, char *data)
+{
+ int src_stride = PixmapBytePad(w, depth);
+
+ if (uxa_do_put_image(pDrawable, pGC, depth, dx, dy, sw, sh, format, data +
+ sy * src_stride + sx * BitsPerPixel(depth) / 8,
+ src_stride))
+ return TRUE;
+
+ if (format == ZPixmap)
+ {
+ PixmapPtr pPixmap;
+
+ pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth,
+ BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data);
+ if (!pPixmap)
+ return FALSE;
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+
+ fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy);
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+
+ FreeScratchPixmapHeader(pPixmap);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to
+ * inform any interested parties of the damage incurred to the drawable.
+ *
+ * We also need to set the pending damage to ensure correct migration in all
+ * cases.
+ */
+void
+uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
+ int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
+ char *data)
+{
+ if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh,
+ dx, dy, data)) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
+ data);
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+ }
+}
+
+ShmFuncs uxa_shm_funcs = { NULL, uxa_shm_put_image };
+
+#endif
+
+static void
+uxa_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int leftPad, int format, char *bits)
+{
+#ifdef MITSHM
+ if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y,
+ bits))
+#else
+ if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits,
+ PixmapBytePad(w, pDrawable->depth)))
+#endif
+ uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+ bits);
+}
+
+static Bool inline
+uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+ GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ int dirsetup;
+
+ /* Need to get both pixmaps to call the driver routines */
+ pSrcPixmap = uxa_get_offscreen_pixmap (pSrcDrawable, &src_off_x, &src_off_y);
+ pDstPixmap = uxa_get_offscreen_pixmap (pDstDrawable, &dst_off_x, &dst_off_y);
+ if (!pSrcPixmap || !pDstPixmap)
+ return FALSE;
+
+ /*
+ * Now the case of a chip that only supports xdir = ydir = 1 or
+ * xdir = ydir = -1, but we have xdir != ydir.
+ */
+ dirsetup = 0; /* No direction set up yet. */
+ for (; nbox; pbox++, nbox--) {
+ if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = -1 blit instead. */
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = 1 blit instead. */
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx >= 0) {
+ /*
+ * xdir = 1, ydir = -1.
+ * Perform line-by-line xdir = ydir = 1 blits, going up.
+ */
+ int i;
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ } else {
+ /*
+ * xdir = -1, ydir = 1.
+ * Perform line-by-line xdir = ydir = -1 blits, going down.
+ */
+ int i;
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = 0; i < pbox->y2 - pbox->y1; i++)
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ }
+ }
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ uxa_mark_sync(pDstDrawable->pScreen);
+ return TRUE;
+}
+
+void
+uxa_copy_n_to_n (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ PixmapPtr pSrcPixmap, pDstPixmap;
+
+ pSrcPixmap = uxa_get_drawable_pixmap (pSrcDrawable);
+ pDstPixmap = uxa_get_drawable_pixmap (pDstDrawable);
+
+ uxa_get_drawable_deltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
+ uxa_get_drawable_deltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
+
+ /* Mixed directions must be handled specially if the card is lame */
+ if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) &&
+ reverse != upsidedown) {
+ if (uxa_copy_n_to_n_two_dir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ dx, dy))
+ return;
+ goto fallback;
+ }
+
+ if (!uxa_pixmap_is_offscreen(pSrcPixmap) ||
+ !uxa_pixmap_is_offscreen(pDstPixmap) ||
+ !(*uxa_screen->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
+ upsidedown ? -1 : 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES)) {
+ goto fallback;
+ }
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Copy) (pDstPixmap,
+ pbox->x1 + dx + src_off_x,
+ pbox->y1 + dy + src_off_y,
+ pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ (*uxa_screen->info->DoneCopy) (pDstPixmap);
+ uxa_mark_sync (pDstDrawable->pScreen);
+
+ return;
+
+fallback:
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+ uxa_drawable_location(pSrcDrawable),
+ uxa_drawable_location(pDstDrawable)));
+ uxa_prepare_access (pDstDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrcDrawable, UXA_PREPARE_SRC);
+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
+ upsidedown, bitplane, closure);
+ uxa_finish_access (pSrcDrawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDstDrawable, UXA_PREPARE_DEST);
+}
+
+RegionPtr
+uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+
+ if (uxa_screen->swappedOut) {
+ return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+ }
+
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, uxa_copy_n_to_n, 0, NULL);
+}
+
+static void
+uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ int i;
+ xRectangle *prect;
+
+ /* If we can't reuse the current GC as is, don't bother accelerating the
+ * points.
+ */
+ if (pGC->fillStyle != FillSolid) {
+ uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = xalloc(sizeof(xRectangle) * npt);
+ for (i = 0; i < npt; i++) {
+ prect[i].x = ppt[i].x;
+ prect[i].y = ppt[i].y;
+ if (i > 0 && mode == CoordModePrevious) {
+ prect[i].x += prect[i - 1].x;
+ prect[i].y += prect[i - 1].y;
+ }
+ prect[i].width = 1;
+ prect[i].height = 1;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
+ xfree(prect);
+}
+
+/**
+ * uxa_poly_lines() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ xRectangle *prect;
+ int x1, x2, y1, y2;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ pGC->fillStyle != FillSolid) {
+ uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = xalloc(sizeof(xRectangle) * (npt - 1));
+ x1 = ppt[0].x;
+ y1 = ppt[0].y;
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < npt - 1; i++) {
+ if (mode == CoordModePrevious) {
+ x2 = x1 + ppt[i + 1].x;
+ y2 = y1 + ppt[i + 1].y;
+ } else {
+ x2 = ppt[i + 1].x;
+ y2 = ppt[i + 1].y;
+ }
+
+ if (x1 != x2 && y1 != y2) {
+ xfree(prect);
+ uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ if (x1 < x2) {
+ prect[i].x = x1;
+ prect[i].width = x2 - x1 + 1;
+ } else {
+ prect[i].x = x2;
+ prect[i].width = x1 - x2 + 1;
+ }
+ if (y1 < y2) {
+ prect[i].y = y1;
+ prect[i].height = y2 - y1 + 1;
+ } else {
+ prect[i].y = y2;
+ prect[i].height = y1 - y2 + 1;
+ }
+
+ x1 = x2;
+ y1 = y2;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
+ xfree(prect);
+}
+
+/**
+ * uxa_poly_segment() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+uxa_poly_segment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg)
+{
+ xRectangle *prect;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ pGC->fillStyle != FillSolid)
+ {
+ uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
+ uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+ }
+
+ prect = xalloc(sizeof(xRectangle) * nseg);
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 < pSeg[i].x2) {
+ prect[i].x = pSeg[i].x1;
+ prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
+ } else {
+ prect[i].x = pSeg[i].x2;
+ prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
+ }
+ if (pSeg[i].y1 < pSeg[i].y2) {
+ prect[i].y = pSeg[i].y1;
+ prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
+ } else {
+ prect[i].y = pSeg[i].y2;
+ prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
+ }
+
+ /* don't paint last pixel */
+ if (pGC->capStyle == CapNotLast) {
+ if (prect[i].width == 1)
+ prect[i].height--;
+ else
+ prect[i].width--;
+ }
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
+ xfree(prect);
+}
+
+static Bool uxa_fill_region_solid (DrawablePtr pDrawable, RegionPtr pRegion,
+ Pixel pixel, CARD32 planemask, CARD32 alu);
+
+static void
+uxa_poly_fill_rect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable);
+ register BoxPtr pbox;
+ BoxPtr pextent;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1, fullY2;
+ int partX1, partX2, partY1, partY2;
+ int xoff, yoff;
+ int xorg, yorg;
+ int n;
+ RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
+
+ /* Compute intersection of rects and clip region */
+ REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
+ REGION_INTERSECT(pScreen, pReg, pClip, pReg);
+
+ if (!REGION_NUM_RECTS(pReg))
+ goto out;
+
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+
+ if (uxa_screen->swappedOut)
+ goto fallback;
+
+ /* For ROPs where overlaps don't matter, convert rectangles to region and
+ * call uxa_fill_region_{solid,tiled}.
+ */
+ if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
+ (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
+ pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
+ pGC->alu == GXset)) {
+ if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
+ uxa_fill_region_solid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
+ pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
+ pGC->alu)) ||
+ (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
+ uxa_fill_region_tiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
+ pGC->planemask, pGC->alu))) {
+ goto out;
+ }
+ }
+
+ if (pGC->fillStyle != FillSolid &&
+ !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
+ {
+ goto fallback;
+ }
+
+ if (!uxa_pixmap_is_offscreen (pPixmap) ||
+ !(*uxa_screen->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+fallback:
+ uxa_check_poly_fill_rect (pDrawable, pGC, nrect, prect);
+ goto out;
+ }
+
+ 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)
+ {
+ (*uxa_screen->info->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(),
+ * but rectangles may overlap each other here.
+ */
+ while(n--)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+ partY1 = pbox->y1;
+ if (partY1 < fullY1)
+ partY1 = fullY1;
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+ partY2 = pbox->y2;
+ if (partY2 > fullY2)
+ partY2 = fullY2;
+
+ pbox++;
+
+ if (partX1 < partX2 && partY1 < partY2) {
+ (*uxa_screen->info->Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+out:
+ REGION_UNINIT(pScreen, pReg);
+ REGION_DESTROY(pScreen, pReg);
+}
+
+const GCOps uxa_ops = {
+ uxa_fill_spans,
+ uxa_check_set_spans,
+ uxa_put_image,
+ uxa_copy_area,
+ uxa_check_copy_plane,
+ uxa_poly_point,
+ uxa_poly_lines,
+ uxa_poly_segment,
+ miPolyRectangle,
+ uxa_check_poly_arc,
+ miFillPolygon,
+ uxa_poly_fill_rect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ uxa_check_image_glyph_blt,
+ uxa_check_poly_glyph_blt,
+ uxa_check_push_pixels,
+};
+
+void
+uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+ 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,
+ NULL,
+ &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+static Bool
+uxa_fill_region_solid (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ Pixel pixel,
+ CARD32 planemask,
+ CARD32 alu)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ int xoff, yoff;
+ Bool ret = FALSE;
+
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+ if (uxa_pixmap_is_offscreen (pPixmap) &&
+ (*uxa_screen->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
+ {
+ int nbox;
+ BoxPtr pBox;
+
+ nbox = REGION_NUM_RECTS (pRegion);
+ pBox = REGION_RECTS (pRegion);
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
+ pBox->y2);
+ pBox++;
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+ ret = TRUE;
+ }
+
+ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+
+ return ret;
+}
+
+/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
+ * Based on fbFillRegionTiled(), fbTile().
+ */
+Bool
+uxa_fill_region_tiled (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ PixmapPtr pTile,
+ DDXPointPtr pPatOrg,
+ CARD32 planemask,
+ CARD32 alu)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ int xoff, yoff;
+ int tileWidth, tileHeight;
+ int nbox = REGION_NUM_RECTS (pRegion);
+ BoxPtr pBox = REGION_RECTS (pRegion);
+ Bool ret = FALSE;
+
+ tileWidth = pTile->drawable.width;
+ tileHeight = pTile->drawable.height;
+
+ /* If we're filling with a solid color, grab it out and go to
+ * FillRegionSolid, saving numerous copies.
+ */
+ if (tileWidth == 1 && tileHeight == 1)
+ return uxa_fill_region_solid(pDrawable, pRegion,
+ uxa_get_pixmap_first_pixel (pTile), planemask,
+ alu);
+
+ pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+ pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPixmap || !uxa_pixmap_is_offscreen(pTile))
+ goto out;
+
+ if ((*uxa_screen->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
+ {
+ while (nbox--)
+ {
+ int height = pBox->y2 - pBox->y1;
+ int dstY = pBox->y1;
+ int tileY;
+
+ modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
+
+ while (height > 0) {
+ int width = pBox->x2 - pBox->x1;
+ int dstX = pBox->x1;
+ int tileX;
+ int h = tileHeight - tileY;
+
+ if (h > height)
+ h = height;
+ height -= h;
+
+ modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
+ tileX);
+
+ while (width > 0) {
+ int w = tileWidth - tileX;
+ if (w > width)
+ w = width;
+ width -= w;
+
+ (*uxa_screen->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
+ w, h);
+ dstX += w;
+ tileX = 0;
+ }
+ dstY += h;
+ tileY = 0;
+ }
+ pBox++;
+ }
+ (*uxa_screen->info->DoneCopy) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+ ret = TRUE;
+ }
+
+out:
+ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+
+ return ret;
+}
+
+
+/**
+ * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
+ *
+ * This is probably the only case we actually care about. The rest fall through
+ * to migration and fbGetImage, which hopefully will result in migration pushing
+ * the pixmap out of framebuffer.
+ */
+void
+uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ BoxRec Box;
+ PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable);
+ int xoff, yoff;
+ Bool ok;
+
+ uxa_get_drawable_deltas (pDrawable, pPix, &xoff, &yoff);
+
+ Box.x1 = pDrawable->y + x + xoff;
+ Box.y1 = pDrawable->y + y + yoff;
+ Box.x2 = Box.x1 + w;
+ Box.y2 = Box.y1 + h;
+
+ if (uxa_screen->swappedOut)
+ goto fallback;
+
+ pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (pPix == NULL || uxa_screen->info->DownloadFromScreen == NULL)
+ goto fallback;
+
+ /* Only cover the ZPixmap, solid copy case. */
+ if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask))
+ goto fallback;
+
+ /* Only try to handle the 8bpp and up cases, since we don't want to think
+ * about <8bpp.
+ */
+ if (pDrawable->bitsPerPixel < 8)
+ goto fallback;
+
+ ok = uxa_screen->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
+ pDrawable->y + y + yoff, w, h, d,
+ PixmapBytePad(w, pDrawable->depth));
+ if (ok) {
+ uxa_wait_sync(pDrawable->pScreen);
+ goto out;
+ }
+
+fallback:
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_SRC);
+ fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+ uxa_finish_access (pDrawable, UXA_PREPARE_SRC);
+
+out:
+ return;
+}
diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c
new file mode 100644
index 00000000..3c446405
--- /dev/null
+++ b/uxa/uxa-glyphs.c
@@ -0,0 +1,880 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ * Partly based on code Copyright © 2000 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor <otaylor@fishsoup.net>
+ * Based on code by: Keith Packard
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+
+#include "mipict.h"
+
+#if DEBUG_GLYPH_CACHE
+#define DBG_GLYPH_CACHE(a) ErrorF a
+#else
+#define DBG_GLYPH_CACHE(a)
+#endif
+
+/* Width of the pixmaps we use for the caches; this should be less than
+ * max texture size of the driver; this may need to actually come from
+ * the driver.
+ */
+#define CACHE_PICTURE_WIDTH 1024
+
+/* Maximum number of glyphs we buffer on the stack before flushing
+ * rendering to the mask or destination surface.
+ */
+#define GLYPH_BUFFER_SIZE 256
+
+typedef struct {
+ PicturePtr source;
+ uxa_composite_rect_t rects[GLYPH_BUFFER_SIZE];
+ int count;
+} uxa_glyph_buffer_t;
+
+typedef enum {
+ UXA_GLYPH_SUCCESS, /* Glyph added to render buffer */
+ UXA_GLYPH_FAIL, /* out of memory, etc */
+ UXA_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */
+} uxa_glyph_cache_result_t;
+
+void
+uxa_glyphs_init(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i = 0;
+
+ memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
+
+ uxa_screen->glyphCaches[i].format = PICT_a8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32;
+ i++;
+
+ assert(i == UXA_NUM_GLYPH_CACHES);
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_screen->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / uxa_screen->glyphCaches[i].glyphWidth;
+ uxa_screen->glyphCaches[i].size = 256;
+ uxa_screen->glyphCaches[i].hashSize = 557;
+ }
+}
+
+static void
+uxa_unrealize_glyph_caches(ScreenPtr pScreen,
+ unsigned int format)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (cache->format != format)
+ continue;
+
+ if (cache->picture) {
+ FreePicture ((pointer) cache->picture, (XID) 0);
+ cache->picture = NULL;
+ }
+
+ if (cache->hashEntries) {
+ xfree(cache->hashEntries);
+ cache->hashEntries = NULL;
+ }
+
+ if (cache->glyphs) {
+ xfree(cache->glyphs);
+ cache->glyphs = NULL;
+ }
+ cache->glyphCount = 0;
+ }
+}
+
+/* All caches for a single format share a single pixmap for glyph storage,
+ * allowing mixing glyphs of different sizes without paying a penalty
+ * for switching between source pixmaps. (Note that for a size of font
+ * right at the border between two sizes, we might be switching for almost
+ * every glyph.)
+ *
+ * This function allocates the storage pixmap, and then fills in the
+ * rest of the allocated structures for all caches with the given format.
+ */
+static Bool
+uxa_realize_glyph_caches(ScreenPtr pScreen,
+ unsigned int format)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int depth = PIXMAN_FORMAT_DEPTH(format);
+ PictFormatPtr pPictFormat;
+ PixmapPtr pPixmap;
+ PicturePtr pPicture;
+ int height;
+ int i;
+ int error;
+
+ pPictFormat = PictureMatchFormat(pScreen, depth, format);
+ if (!pPictFormat)
+ return FALSE;
+
+ /* Compute the total vertical size needed for the format */
+
+ height = 0;
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+ int rows;
+
+ if (cache->format != format)
+ continue;
+
+ cache->yOffset = height;
+
+ rows = (cache->size + cache->columns - 1) / cache->columns;
+ height += rows * cache->glyphHeight;
+ }
+
+ /* Now allocate the pixmap and picture */
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen,
+ CACHE_PICTURE_WIDTH,
+ height, depth, 0);
+ if (!pPixmap)
+ return FALSE;
+
+ pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
+ 0, 0, serverClient, &error);
+
+ (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
+
+ if (!pPicture)
+ return FALSE;
+
+ /* And store the picture in all the caches for the format */
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+ int j;
+
+ if (cache->format != format)
+ continue;
+
+ cache->picture = pPicture;
+ cache->picture->refcnt++;
+ cache->hashEntries = xalloc(sizeof(int) * cache->hashSize);
+ cache->glyphs = xalloc(sizeof(uxa_cached_glyph_t) * cache->size);
+ cache->glyphCount = 0;
+
+ if (!cache->hashEntries || !cache->glyphs)
+ goto bail;
+
+ for (j = 0; j < cache->hashSize; j++)
+ cache->hashEntries[j] = -1;
+
+ cache->evictionPosition = rand() % cache->size;
+ }
+
+ /* Each cache references the picture individually */
+ FreePicture ((pointer) pPicture, (XID) 0);
+ return TRUE;
+
+bail:
+ uxa_unrealize_glyph_caches(pScreen, format);
+ return FALSE;
+}
+
+void
+uxa_glyphs_fini (ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (cache->picture)
+ uxa_unrealize_glyph_caches(pScreen, cache->format);
+ }
+}
+
+static int
+uxa_glyph_cache_hash_lookup(uxa_glyph_cache_t *cache, GlyphPtr pGlyph)
+{
+ int slot;
+
+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ int entryPos = cache->hashEntries[slot];
+ if (entryPos == -1)
+ return -1;
+
+ if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
+ return entryPos;
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+static void
+uxa_glyph_cache_hash_insert(uxa_glyph_cache_t *cache,
+ GlyphPtr pGlyph,
+ int pos)
+{
+ int slot;
+
+ memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
+
+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ if (cache->hashEntries[slot] == -1) {
+ cache->hashEntries[slot] = pos;
+ return;
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+static void
+uxa_glyph_cache_hash_remove(uxa_glyph_cache_t *cache,
+ int pos)
+{
+ int slot;
+ int emptiedSlot = -1;
+
+ slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ int entryPos = cache->hashEntries[slot];
+
+ if (entryPos == -1)
+ return;
+
+ if (entryPos == pos) {
+ cache->hashEntries[slot] = -1;
+ emptiedSlot = slot;
+ } else if (emptiedSlot != -1) {
+ /* See if we can move this entry into the emptied slot, we can't
+ * do that if if entry would have hashed between the current position
+ * and the emptied slot. (taking wrapping into account). Bad positions
+ * are:
+ *
+ * | XXXXXXXXXX |
+ * i j
+ *
+ * |XXX XXXX|
+ * j i
+ *
+ * i - slot, j - emptiedSlot
+ *
+ * (Knuth 6.4R)
+ */
+
+ int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
+
+ if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
+ (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot))))
+ {
+ cache->hashEntries[emptiedSlot] = entryPos;
+ cache->hashEntries[slot] = -1;
+ emptiedSlot = slot;
+ }
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
+#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
+
+/* The most efficient thing to way to upload the glyph to the screen
+ * is to use the UploadToScreen() driver hook; this allows us to
+ * pipeline glyph uploads and to avoid creating offscreen pixmaps for
+ * glyphs that we'll never use again.
+ */
+static Bool
+uxa_glyph_cache_upload_glyph(ScreenPtr pScreen,
+ uxa_glyph_cache_t *cache,
+ int pos,
+ GlyphPtr pGlyph)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum];
+ PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable;
+ PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable;
+ int cacheXoff, cacheYoff;
+
+ if (!uxa_screen->info->UploadToScreen || uxa_screen->swappedOut)
+ return FALSE;
+
+ /* If the glyph pixmap is already uploaded, no point in doing
+ * things this way */
+ if (uxa_pixmap_is_offscreen(pGlyphPixmap))
+ return FALSE;
+
+ /* UploadToScreen only works if bpp match */
+ if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
+ return FALSE;
+
+ pCachePixmap = uxa_get_offscreen_pixmap ((DrawablePtr)pCachePixmap, &cacheXoff, &cacheYoff);
+ if (!pCachePixmap)
+ return FALSE;
+
+ if (!uxa_screen->info->UploadToScreen(pCachePixmap,
+ CACHE_X(pos) + cacheXoff,
+ CACHE_Y(pos) + cacheYoff,
+ pGlyph->info.width,
+ pGlyph->info.height,
+ (char *)pGlyphPixmap->devPrivate.ptr,
+ pGlyphPixmap->devKind))
+ return FALSE;
+
+ return TRUE;
+}
+
+static uxa_glyph_cache_result_t
+uxa_glyph_cache_buffer_glyph(ScreenPtr pScreen,
+ uxa_glyph_cache_t *cache,
+ uxa_glyph_buffer_t *buffer,
+ GlyphPtr pGlyph,
+ int xGlyph,
+ int yGlyph)
+{
+ uxa_composite_rect_t *rect;
+ int pos;
+
+ if (buffer->source && buffer->source != cache->picture)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ if (!cache->picture) {
+ if (!uxa_realize_glyph_caches(pScreen, cache->format))
+ return UXA_GLYPH_FAIL;
+ }
+
+ DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
+ cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB",
+ (long)*(CARD32 *) pGlyph->sha1));
+
+ pos = uxa_glyph_cache_hash_lookup(cache, pGlyph);
+ if (pos != -1) {
+ DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
+ } else {
+ if (cache->glyphCount < cache->size) {
+ /* Space remaining; we fill from the start */
+ pos = cache->glyphCount;
+ cache->glyphCount++;
+ DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
+
+ uxa_glyph_cache_hash_insert(cache, pGlyph, pos);
+
+ } else {
+ /* Need to evict an entry. We have to see if any glyphs
+ * already in the output buffer were at this position in
+ * the cache
+ */
+
+ pos = cache->evictionPosition;
+ DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
+ if (buffer->count) {
+ int x, y;
+ int i;
+
+ x = CACHE_X(pos);
+ y = CACHE_Y(pos);
+
+ for (i = 0; i < buffer->count; i++) {
+ if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
+ DBG_GLYPH_CACHE((" must flush buffer\n"));
+ return UXA_GLYPH_NEED_FLUSH;
+ }
+ }
+ }
+
+ /* OK, we're all set, swap in the new glyph */
+ uxa_glyph_cache_hash_remove(cache, pos);
+ uxa_glyph_cache_hash_insert(cache, pGlyph, pos);
+
+ /* And pick a new eviction position */
+ cache->evictionPosition = rand() % cache->size;
+ }
+
+ /* Now actually upload the glyph into the cache picture; if
+ * we can't do it with UploadToScreen (because the glyph is
+ * offscreen, etc), we fall back to CompositePicture.
+ */
+ if (!uxa_glyph_cache_upload_glyph(pScreen, cache, pos, pGlyph)) {
+ CompositePicture (PictOpSrc,
+ GlyphPicture(pGlyph)[pScreen->myNum],
+ None,
+ cache->picture,
+ 0, 0,
+ 0, 0,
+ CACHE_X(pos),
+ CACHE_Y(pos),
+ pGlyph->info.width,
+ pGlyph->info.height);
+ }
+
+ }
+
+
+ buffer->source = cache->picture;
+
+ rect = &buffer->rects[buffer->count];
+ rect->xSrc = CACHE_X(pos);
+ rect->ySrc = CACHE_Y(pos);
+ rect->xDst = xGlyph - pGlyph->info.x;
+ rect->yDst = yGlyph - pGlyph->info.y;
+ rect->width = pGlyph->info.width;
+ rect->height = pGlyph->info.height;
+
+ buffer->count++;
+
+ return UXA_GLYPH_SUCCESS;
+}
+
+#undef CACHE_X
+#undef CACHE_Y
+
+static uxa_glyph_cache_result_t
+uxa_buffer_glyph(ScreenPtr pScreen,
+ uxa_glyph_buffer_t *buffer,
+ GlyphPtr pGlyph,
+ int xGlyph,
+ int yGlyph)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
+ int width = pGlyph->info.width;
+ int height = pGlyph->info.height;
+ uxa_composite_rect_t *rect;
+ PicturePtr source;
+ int i;
+
+ if (buffer->count == GLYPH_BUFFER_SIZE)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ if (PICT_FORMAT_BPP(format) == 1)
+ format = PICT_a8;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (format == cache->format &&
+ width <= cache->glyphWidth &&
+ height <= cache->glyphHeight) {
+ uxa_glyph_cache_result_t result = uxa_glyph_cache_buffer_glyph(pScreen, &uxa_screen->glyphCaches[i],
+ buffer,
+ pGlyph, xGlyph, yGlyph);
+ switch (result) {
+ case UXA_GLYPH_FAIL:
+ break;
+ case UXA_GLYPH_SUCCESS:
+ case UXA_GLYPH_NEED_FLUSH:
+ return result;
+ }
+ }
+ }
+
+ /* Couldn't find the glyph in the cache, use the glyph picture directly */
+
+ source = GlyphPicture(pGlyph)[pScreen->myNum];
+ if (buffer->source && buffer->source != source)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ buffer->source = source;
+
+ rect = &buffer->rects[buffer->count];
+ rect->xSrc = 0;
+ rect->ySrc = 0;
+ rect->xDst = xGlyph - pGlyph->info.x;
+ rect->yDst = yGlyph - pGlyph->info.y;
+ rect->width = pGlyph->info.width;
+ rect->height = pGlyph->info.height;
+
+ buffer->count++;
+
+ return UXA_GLYPH_SUCCESS;
+}
+
+static void
+uxa_glyphs_to_mask(PicturePtr pMask,
+ uxa_glyph_buffer_t *buffer)
+{
+ uxa_composite_rects(PictOpAdd, buffer->source, pMask,
+ buffer->count, buffer->rects);
+
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+static void
+uxa_glyphs_to_dst(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ uxa_glyph_buffer_t *buffer,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xDst,
+ INT16 yDst)
+{
+ int i;
+
+ for (i = 0; i < buffer->count; i++) {
+ uxa_composite_rect_t *rect = &buffer->rects[i];
+
+ CompositePicture (op,
+ pSrc,
+ buffer->source,
+ pDst,
+ xSrc + rect->xDst - xDst,
+ ySrc + rect->yDst - yDst,
+ rect->xSrc,
+ rect->ySrc,
+ rect->xDst,
+ rect->yDst,
+ rect->width,
+ rect->height);
+ }
+
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+/* Cut and paste from render/glyph.c - probably should export it instead */
+static void
+uxa_glyph_extents (int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs,
+ BoxPtr extents)
+{
+ int x1, x2, y1, y2;
+ int n;
+ GlyphPtr glyph;
+ int x, y;
+
+ x = 0;
+ y = 0;
+ extents->x1 = MAXSHORT;
+ extents->x2 = MINSHORT;
+ extents->y1 = MAXSHORT;
+ extents->y2 = MINSHORT;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--)
+ {
+ glyph = *glyphs++;
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ x2 = x1 + glyph->info.width;
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ y2 = y1 + glyph->info.height;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+ if (x1 < extents->x1)
+ extents->x1 = x1;
+ if (x2 > extents->x2)
+ extents->x2 = x2;
+ if (y1 < extents->y1)
+ extents->y1 = y1;
+ if (y2 > extents->y2)
+ extents->y2 = y2;
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+}
+
+/**
+ * Returns TRUE if the glyphs in the lists intersect. Only checks based on
+ * bounding box, which appears to be good enough to catch most cases at least.
+ */
+static Bool
+uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+ int x1, x2, y1, y2;
+ int n;
+ GlyphPtr glyph;
+ int x, y;
+ BoxRec extents;
+ Bool first = TRUE;
+
+ x = 0;
+ y = 0;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ glyph = *glyphs++;
+
+ if (glyph->info.width == 0 || glyph->info.height == 0) {
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ continue;
+ }
+
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ x2 = x1 + glyph->info.width;
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ y2 = y1 + glyph->info.height;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+
+ if (first) {
+ extents.x1 = x1;
+ extents.y1 = y1;
+ extents.x2 = x2;
+ extents.y2 = y2;
+ first = FALSE;
+ } else {
+ if (x1 < extents.x2 && x2 > extents.x1 &&
+ y1 < extents.y2 && y2 > extents.y1)
+ {
+ return TRUE;
+ }
+
+ if (x1 < extents.x1)
+ extents.x1 = x1;
+ if (x2 > extents.x2)
+ extents.x2 = x2;
+ if (y1 < extents.y1)
+ extents.y1 = y1;
+ if (y2 > extents.y2)
+ extents.y2 = y2;
+ }
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+
+ return FALSE;
+}
+
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+
+void
+uxa_glyphs (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs)
+{
+ PicturePtr pPicture;
+ PixmapPtr pMaskPixmap = 0;
+ PicturePtr pMask;
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ int width = 0, height = 0;
+ int x, y;
+ int xDst = list->xOff, yDst = list->yOff;
+ int n;
+ GlyphPtr glyph;
+ int error;
+ BoxRec extents = {0, 0, 0, 0};
+ CARD32 component_alpha;
+ uxa_glyph_buffer_t buffer;
+
+ /* If we don't have a mask format but all the glyphs have the same format
+ * and don't intersect, use the glyph format as mask format for the full
+ * benefits of the glyph cache.
+ */
+ if (!maskFormat) {
+ Bool sameFormat = TRUE;
+ int i;
+
+ maskFormat = list[0].format;
+
+ for (i = 0; i < nlist; i++) {
+ if (maskFormat->format != list[i].format->format) {
+ sameFormat = FALSE;
+ break;
+ }
+ }
+
+ if (!sameFormat || (maskFormat->depth != 1 &&
+ uxa_glyphs_intersect(nlist, list, glyphs))) {
+ maskFormat = NULL;
+ }
+ }
+
+ if (maskFormat)
+ {
+ GCPtr pGC;
+ xRectangle rect;
+
+ uxa_glyph_extents (nlist, list, glyphs, &extents);
+
+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ return;
+ width = extents.x2 - extents.x1;
+ height = extents.y2 - extents.y1;
+
+ if (maskFormat->depth == 1) {
+ PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8);
+
+ if (a8Format)
+ maskFormat = a8Format;
+ }
+
+ pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ maskFormat->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pMaskPixmap)
+ return;
+ component_alpha = NeedsComponent(maskFormat->format);
+ pMask = CreatePicture (0, &pMaskPixmap->drawable,
+ maskFormat, CPComponentAlpha, &component_alpha,
+ serverClient, &error);
+ if (!pMask)
+ {
+ (*pScreen->DestroyPixmap) (pMaskPixmap);
+ return;
+ }
+ pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
+ ValidateGC (&pMaskPixmap->drawable, pGC);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
+ FreeScratchGC (pGC);
+ x = -extents.x1;
+ y = -extents.y1;
+ }
+ else
+ {
+ pMask = pDst;
+ x = 0;
+ y = 0;
+ }
+ buffer.count = 0;
+ buffer.source = NULL;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--)
+ {
+ glyph = *glyphs++;
+ pPicture = GlyphPicture (glyph)[pScreen->myNum];
+
+ if (glyph->info.width > 0 && glyph->info.height > 0 &&
+ uxa_buffer_glyph(pScreen, &buffer, glyph, x, y) == UXA_GLYPH_NEED_FLUSH)
+ {
+ if (maskFormat)
+ uxa_glyphs_to_mask(pMask, &buffer);
+ else
+ uxa_glyphs_to_dst(op, pSrc, pDst, &buffer,
+ xSrc, ySrc, xDst, yDst);
+
+ uxa_buffer_glyph(pScreen, &buffer, glyph, x, y);
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ if (maskFormat)
+ uxa_glyphs_to_mask(pMask, &buffer);
+ else
+ uxa_glyphs_to_dst(op, pSrc, pDst, &buffer,
+ xSrc, ySrc, xDst, yDst);
+
+ if (maskFormat)
+ {
+ x = extents.x1;
+ y = extents.y1;
+ CompositePicture (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc + x - xDst,
+ ySrc + y - yDst,
+ 0, 0,
+ x, y,
+ width, height);
+ FreePicture ((pointer) pMask, (XID) 0);
+ (*pScreen->DestroyPixmap) (pMaskPixmap);
+ }
+}
diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h
new file mode 100644
index 00000000..acc82bba
--- /dev/null
+++ b/uxa/uxa-priv.h
@@ -0,0 +1,444 @@
+/*
+ *
+ * Copyright © 2000,2008 Keith Packard
+ * 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 UXAPRIV_H
+#define UXAPRIV_H
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+
+#include "uxa.h"
+
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#ifdef MITSHM
+#define _XSHM_SERVER_
+#include <X11/extensions/shmstr.h>
+#endif
+#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"
+#ifdef RENDER
+//#include "fbpict.h"
+#include "glyphstr.h"
+#endif
+#include "damage.h"
+
+#define DEBUG_TRACE_FALL 0
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#define DEBUG_OFFSCREEN 0
+#define DEBUG_GLYPH_CACHE 0
+
+#if DEBUG_TRACE_FALL
+#define UXA_FALLBACK(x) \
+do { \
+ ErrorF("UXA fallback at %s: ", __FUNCTION__); \
+ ErrorF x; \
+} while (0)
+
+char
+uxa_drawable_location(DrawablePtr pDrawable);
+#else
+#define UXA_FALLBACK(x)
+#endif
+
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+
+typedef struct {
+ unsigned char sha1[20];
+} uxa_cached_glyph_t;
+
+typedef struct {
+ /* The identity of the cache, statically configured at initialization */
+ unsigned int format;
+ int glyphWidth;
+ int glyphHeight;
+
+ int size; /* Size of cache; eventually this should be dynamically determined */
+
+ /* Hash table mapping from glyph sha1 to position in the glyph; we use
+ * open addressing with a hash table size determined based on size and large
+ * enough so that we always have a good amount of free space, so we can
+ * use linear probing. (Linear probing is preferrable to double hashing
+ * here because it allows us to easily remove entries.)
+ */
+ int *hashEntries;
+ int hashSize;
+
+ uxa_cached_glyph_t *glyphs;
+ int glyphCount; /* Current number of glyphs */
+
+ PicturePtr picture; /* Where the glyphs of the cache are stored */
+ int yOffset; /* y location within the picture where the cache starts */
+ int columns; /* Number of columns the glyphs are layed out in */
+ int evictionPosition; /* Next random position to evict a glyph */
+} uxa_glyph_cache_t;
+
+#define UXA_NUM_GLYPH_CACHES 4
+
+typedef void (*EnableDisableFBAccessProcPtr)(int, Bool);
+typedef struct {
+ uxa_driver_t *info;
+ CreateGCProcPtr SavedCreateGC;
+ CloseScreenProcPtr SavedCloseScreen;
+ GetImageProcPtr SavedGetImage;
+ GetSpansProcPtr SavedGetSpans;
+ CreatePixmapProcPtr SavedCreatePixmap;
+ DestroyPixmapProcPtr SavedDestroyPixmap;
+ CopyWindowProcPtr SavedCopyWindow;
+ ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
+ BitmapToRegionProcPtr SavedBitmapToRegion;
+#ifdef RENDER
+ CompositeProcPtr SavedComposite;
+ TrianglesProcPtr SavedTriangles;
+ GlyphsProcPtr SavedGlyphs;
+ TrapezoidsProcPtr SavedTrapezoids;
+ AddTrapsProcPtr SavedAddTraps;
+#endif
+
+ Bool swappedOut;
+ unsigned disableFbCount;
+ unsigned offScreenCounter;
+
+ uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHES];
+} uxa_screen_t;
+
+/*
+ * 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 DevPrivateKey uxa_screen_key;
+#define uxa_get_screen(s) ((uxa_screen_t *)dixLookupPrivate(&(s)->devPrivates, uxa_screen_key))
+
+/** Align an offset to an arbitrary alignment */
+#define UXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
+ (((offset) + (align) - 1) % (align)))
+/** Align an offset to a power-of-two alignment */
+#define UXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
+
+typedef struct {
+ INT16 xSrc;
+ INT16 ySrc;
+ INT16 xDst;
+ INT16 yDst;
+ INT16 width;
+ INT16 height;
+} uxa_composite_rect_t;
+
+/**
+ * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
+ * to set EXA options or hook in screen functions to handle using EXA as the AA.
+ */
+void exaDDXDriverInit (ScreenPtr pScreen);
+
+void
+uxa_prepare_access_window(WindowPtr pWin);
+
+void
+uxa_finish_access_window(WindowPtr pWin);
+
+/* uxa-unaccel.c */
+void
+uxa_prepare_access_gc(GCPtr pGC);
+
+void
+uxa_finish_access_gc(GCPtr pGC);
+
+void
+uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted);
+
+void
+uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
+
+void
+uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits);
+
+RegionPtr
+uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty);
+
+RegionPtr
+uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane);
+
+void
+uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit);
+
+void
+uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt);
+
+void
+uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit);
+
+void
+uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs);
+
+void
+uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect);
+
+void
+uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y);
+
+void
+uxa_check_get_spans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart);
+
+void
+uxa_check_add_traps (PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off,
+ int ntrap,
+ xTrap *traps);
+
+/* uxa-accel.c */
+
+static _X_INLINE Bool
+uxa_gc_reads_destination(DrawablePtr pDrawable, unsigned long planemask,
+ unsigned int fillStyle, unsigned char alu)
+{
+ return ((alu != GXcopy && alu != GXclear &&alu != GXset &&
+ alu != GXcopyInverted) || fillStyle == FillStippled ||
+ !UXA_PM_IS_SOLID(pDrawable, planemask));
+}
+
+void
+uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
+
+Bool
+uxa_fill_region_tiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
+ DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu);
+
+void
+uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
+ int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
+ char *data);
+
+void
+uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d);
+
+extern const GCOps uxa_ops;
+
+#ifdef MITSHM
+extern ShmFuncs uxa_shm_funcs;
+
+/* XXX these come from shmint.h, which isn't exported by the server */
+void
+ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs);
+
+void
+ShmSetPixmapFormat(ScreenPtr pScreen, int format);
+
+void
+fbShmPutImage(XSHM_PUT_IMAGE_ARGS);
+
+#endif
+
+#ifdef RENDER
+
+/* XXX these are in fbpict.h, which is not installed */
+void
+fbComposite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+
+void
+fbAddTraps (PicturePtr pPicture,
+ INT16 xOff,
+ INT16 yOff,
+ int ntrap,
+ xTrap *traps);
+
+void
+uxa_check_composite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+#endif
+
+/* uxa.c */
+void
+uxa_prepare_access(DrawablePtr pDrawable, int index);
+
+void
+uxa_finish_access(DrawablePtr pDrawable, int index);
+
+void
+uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+ int *xp, int *yp);
+
+Bool
+uxa_drawable_is_offscreen (DrawablePtr pDrawable);
+
+Bool
+uxa_pixmap_is_offscreen(PixmapPtr p);
+
+PixmapPtr
+uxa_get_offscreen_pixmap (DrawablePtr pDrawable, int *xp, int *yp);
+
+PixmapPtr
+uxa_get_drawable_pixmap(DrawablePtr pDrawable);
+
+RegionPtr
+uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty);
+
+void
+uxa_copy_n_to_n (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure);
+
+/* uxa_render.c */
+Bool
+uxa_op_reads_destination (CARD8 op);
+
+void
+uxa_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+
+void
+uxa_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects);
+
+void
+uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntrap, xTrapezoid *traps);
+
+void
+uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntri, xTriangle *tris);
+
+/* uxa_glyph.c */
+void
+uxa_glyphs_init(ScreenPtr pScreen);
+
+void
+uxa_glyphs_fini (ScreenPtr pScreen);
+
+void
+uxa_glyphs (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs);
+
+#endif /* UXAPRIV_H */
diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c
new file mode 100644
index 00000000..38e6088f
--- /dev/null
+++ b/uxa/uxa-render.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+
+#if DEBUG_TRACE_FALL
+static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, int n)
+{
+ char format[20];
+ char size[20];
+ char loc;
+ int temp;
+
+ if (!pict) {
+ snprintf(string, n, "None");
+ return;
+ }
+
+ switch (pict->format)
+ {
+ case PICT_a8r8g8b8:
+ snprintf(format, 20, "ARGB8888");
+ break;
+ case PICT_x8r8g8b8:
+ snprintf(format, 20, "XRGB8888");
+ break;
+ case PICT_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 = uxa_get_drawable_pixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
+
+ snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
+ pict->pDrawable->height, pict->repeat ?
+ " R" : "");
+
+ snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
+}
+
+static void
+uxa_print_composite_fallback(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;
+ }
+
+ uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
+ uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
+ uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
+
+ ErrorF("Composite fallback: op %s, \n"
+ " src %s, \n"
+ " mask %s, \n"
+ " dst %s, \n",
+ sop, srcdesc, maskdesc, dstdesc);
+}
+#endif /* DEBUG_TRACE_FALL */
+
+Bool
+uxa_op_reads_destination (CARD8 op)
+{
+ /* FALSE (does not read destination) is the list of ops in the protocol
+ * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
+ * That's just Clear and Src. ReduceCompositeOp() will already have
+ * converted con/disjoint clear/src to Clear or Src.
+ */
+ switch (op) {
+ case PictOpClear:
+ case PictOpSrc:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+
+static Bool
+uxa_get_pixel_from_rgba(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
+uxa_get_rgba_from_pixel(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
+uxa_try_driver_solid_fill(PicturePtr pSrc,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(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;
+
+ pDstPix = uxa_get_drawable_pixmap (pDst->pDrawable);
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+
+ 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;
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ pixel = uxa_get_pixmap_first_pixel (pSrcPix);
+
+ if (!uxa_pixmap_is_offscreen(pDstPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!uxa_get_rgba_from_pixel(pixel, &red, &green, &blue, &alpha,
+ pSrc->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!uxa_get_pixel_from_rgba(&pixel, red, green, blue, alpha,
+ pDst->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!(*uxa_screen->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
+ pbox++;
+ }
+
+ (*uxa_screen->info->DoneSolid) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+static int
+uxa_try_driver_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pDstPix;
+ struct _Pixmap scratch;
+
+ if (!uxa_screen->info->PrepareComposite)
+ return -1;
+
+ pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
+
+ pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable);
+
+ if (uxa_screen->info->CheckComposite &&
+ !(*uxa_screen->info->CheckComposite) (op, pSrc, NULL, pDst))
+ {
+ return -1;
+ }
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (!uxa_pixmap_is_offscreen(pDstPix))
+ return 0;
+
+ if (!pSrcPix && uxa_screen->info->UploadToScratch)
+ {
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch))
+ pSrcPix = &scratch;
+ }
+
+ if (!pSrcPix)
+ return 0;
+
+ if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix,
+ NULL, pDstPix))
+ return -1;
+
+ while (nrect--)
+ {
+ INT16 xDst = rects->xDst + pDst->pDrawable->x;
+ INT16 yDst = rects->yDst + pDst->pDrawable->y;
+ INT16 xSrc = rects->xSrc + pSrc->pDrawable->x;
+ INT16 ySrc = rects->ySrc + pSrc->pDrawable->y;
+
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+
+ if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ rects->width, rects->height))
+ goto next_rect;
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ xSrc = xSrc + src_off_x - xDst - dst_off_x;
+ ySrc = ySrc + src_off_y - yDst - dst_off_y;
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Composite) (pDstPix,
+ pbox->x1 + xSrc,
+ pbox->y1 + ySrc,
+ 0, 0,
+ pbox->x1,
+ pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ next_rect:
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+
+ rects++;
+ }
+
+ (*uxa_screen->info->DoneComposite) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ return 1;
+}
+
+/**
+ * Copy a number of rectangles from source to destination in a single
+ * operation. This is specialized for building a glyph mask: we don'y
+ * have a mask argument because we don't need it for that, and we
+ * don't have he special-case fallbacks found in uxa_composite() - if the
+ * driver can support it, we use the driver functionality, otherwise we
+ * fallback straight to software.
+ */
+void
+uxa_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects)
+{
+ int n;
+ uxa_composite_rect_t *r;
+
+ /************************************************************/
+
+ ValidatePicture (pSrc);
+ ValidatePicture (pDst);
+
+ if (uxa_try_driver_composite_rects(op, pSrc, pDst, nrect, rects) != 1) {
+ n = nrect;
+ r = rects;
+ while (n--) {
+ uxa_check_composite (op, pSrc, NULL, pDst,
+ r->xSrc, r->ySrc,
+ 0, 0,
+ r->xDst, r->yDst,
+ r->width, r->height);
+ r++;
+ }
+ }
+
+ /************************************************************/
+
+}
+
+static int
+uxa_try_driver_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(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;
+
+ pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
+ pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable);
+ if (pMask)
+ pMaskPix = uxa_get_drawable_pixmap(pMask->pDrawable);
+
+ 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 (uxa_screen->info->CheckComposite &&
+ !(*uxa_screen->info->CheckComposite) (op, pSrc, pMask, pDst))
+ {
+ return -1;
+ }
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ return 1;
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (pMask)
+ pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x,
+ &mask_off_y);
+
+ if (!uxa_pixmap_is_offscreen(pDstPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!pSrcPix && (!pMask || pMaskPix) && uxa_screen->info->UploadToScratch) {
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch))
+ pSrcPix = &scratch;
+ } else if (pSrcPix && pMask && !pMaskPix && uxa_screen->info->UploadToScratch) {
+ pMaskPix = uxa_get_drawable_pixmap (pMask->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pMaskPix, &scratch))
+ pMaskPix = &scratch;
+ }
+
+ if (!pSrcPix || (pMask && !pMaskPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
+ pMaskPix, pDstPix))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ xMask = xMask + mask_off_x - xDst - dst_off_x;
+ yMask = yMask + mask_off_y - yDst - dst_off_y;
+
+ xSrc = xSrc + src_off_x - xDst - dst_off_x;
+ ySrc = ySrc + src_off_y - yDst - dst_off_y;
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Composite) (pDstPix,
+ pbox->x1 + xSrc,
+ pbox->y1 + ySrc,
+ pbox->x1 + xMask,
+ pbox->y1 + yMask,
+ pbox->x1,
+ pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+ (*uxa_screen->info->DoneComposite) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+/**
+ * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
+ * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
+ * alpha and limited 1-tmu cards.
+ *
+ * From http://anholt.livejournal.com/32058.html:
+ *
+ * The trouble is that component-alpha rendering requires two different sources
+ * for blending: one for the source value to the blender, which is the
+ * per-channel multiplication of source and mask, and one for the source alpha
+ * for multiplying with the destination channels, which is the multiplication
+ * of the source channels by the mask alpha. So the equation for Over is:
+ *
+ * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
+ * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
+ * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
+ * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
+ *
+ * But we can do some simpler operations, right? How about PictOpOutReverse,
+ * which has a source factor of 0 and dest factor of (1 - source alpha). We
+ * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
+ * blenders pretty easily. So we can do a component-alpha OutReverse, which
+ * gets us:
+ *
+ * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
+ * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
+ * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
+ * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
+ *
+ * OK. And if an op doesn't use the source alpha value for the destination
+ * factor, then we can do the channel multiplication in the texture blenders
+ * to get the source value, and ignore the source alpha that we wouldn't use.
+ * We've supported this in the Radeon driver for a long time. An example would
+ * be PictOpAdd, which does:
+ *
+ * dst.A = src.A * mask.A + dst.A
+ * dst.R = src.R * mask.R + dst.R
+ * dst.G = src.G * mask.G + dst.G
+ * dst.B = src.B * mask.B + dst.B
+ *
+ * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
+ * after it, we get:
+ *
+ * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
+ * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
+ * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
+ * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
+ */
+
+static int
+uxa_try_magic_two_pass_composite_helper(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+
+ assert(op == PictOpOver);
+
+ if (uxa_screen->info->CheckComposite &&
+ (!(*uxa_screen->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
+ pDst) ||
+ !(*uxa_screen->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
+ {
+ return -1;
+ }
+
+ /* Now, we think we should be able to accelerate this operation. First,
+ * composite the destination to be the destination times the source alpha
+ * factors.
+ */
+ uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ xDst, yDst, width, height);
+
+ /* Then, add in the source value times the destination alpha factors (1.0).
+ */
+ uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ xDst, yDst, width, height);
+
+ return 1;
+}
+
+void
+uxa_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ int ret = -1;
+ Bool saveSrcRepeat = pSrc->repeat;
+ Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
+ RegionRec region;
+
+ /* We currently don't support acceleration of gradients, or other pictures
+ * with a NULL pDrawable.
+ */
+ if (uxa_screen->swappedOut ||
+ pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL))
+ {
+ goto fallback;
+ }
+
+ /* Remove repeat in source if useless */
+ if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
+ (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
+ (ySrc + height) <= pSrc->pDrawable->height)
+ pSrc->repeat = 0;
+
+ if (!pMask)
+ {
+ if ((op == PictOpSrc &&
+ ((pSrc->format == pDst->format) ||
+ (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) ||
+ (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) ||
+ (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap &&
+ pSrc->format == pDst->format &&
+ (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))
+ {
+ if (pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat)
+ {
+ ret = uxa_try_driver_solid_fill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+ else if (pSrc->pDrawable != NULL &&
+ !pSrc->repeat &&
+ !pSrc->transform)
+ {
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst,
+ yDst, width, height))
+ goto done;
+
+
+ uxa_copy_n_to_n (pSrc->pDrawable, pDst->pDrawable, NULL,
+ REGION_RECTS(&region), REGION_NUM_RECTS(&region),
+ xSrc - xDst, ySrc - yDst,
+ FALSE, FALSE, 0, NULL);
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ goto done;
+ }
+ else if (pSrc->pDrawable != NULL &&
+ pSrc->pDrawable->type == DRAWABLE_PIXMAP &&
+ !pSrc->transform &&
+ pSrc->repeatType == RepeatNormal)
+ {
+ DDXPointRec patOrg;
+
+ /* Let's see if the driver can do the repeat in one go */
+ if (uxa_screen->info->PrepareComposite && !pSrc->alphaMap &&
+ !pDst->alphaMap)
+ {
+ ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc,
+ ySrc, xMask, yMask, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+
+ /* Now see if we can use uxa_fill_region_tiled() */
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, xSrc,
+ ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ goto done;
+
+ /* pattern origin is the point in the destination drawable
+ * corresponding to (0,0) in the source */
+ patOrg.x = xDst - xSrc;
+ patOrg.y = yDst - ySrc;
+
+ ret = uxa_fill_region_tiled(pDst->pDrawable, &region,
+ (PixmapPtr)pSrc->pDrawable,
+ &patOrg, FB_ALLONES, GXcopy);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+
+ if (ret)
+ goto done;
+ }
+ }
+ }
+
+ /* Remove repeat in mask if useless */
+ if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
+ (xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
+ (yMask + height) <= pMask->pDrawable->height)
+ pMask->repeat = 0;
+
+ if (uxa_screen->info->PrepareComposite &&
+ !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
+ {
+ Bool isSrcSolid;
+
+ ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
+ yMask, xDst, yDst, width, height);
+ if (ret == 1)
+ goto done;
+
+ /* For generic masks and solid src pictures, mach64 can do Over in two
+ * passes, similar to the component-alpha case.
+ */
+ isSrcSolid = pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat;
+
+ /* If we couldn't do the Composite in a single pass, and it was a
+ * component-alpha Over, see if we can do it in two passes with
+ * an OutReverse and then an Add.
+ */
+ if (ret == -1 && op == PictOpOver && pMask &&
+ (pMask->componentAlpha || isSrcSolid)) {
+ ret = uxa_try_magic_two_pass_composite_helper(op, pSrc, pMask, pDst,
+ xSrc, ySrc,
+ xMask, yMask, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+ }
+
+fallback:
+#if DEBUG_TRACE_FALL
+ uxa_print_composite_fallback (op, pSrc, pMask, pDst);
+#endif
+
+ uxa_check_composite (op, pSrc, pMask, pDst, xSrc, ySrc,
+ xMask, yMask, xDst, yDst, width, height);
+
+done:
+ pSrc->repeat = saveSrcRepeat;
+ if (pMask)
+ pMask->repeat = saveMaskRepeat;
+}
+#endif
+
+/**
+ * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
+ * of PolyFillRect to initialize the pixmap after creating it, to prevent
+ * the pixmap from being migrated.
+ *
+ * See the comments about uxa_trapezoids and uxa_triangles.
+ */
+static PicturePtr
+uxa_create_alpha_picture (ScreenPtr pScreen,
+ PicturePtr pDst,
+ PictFormatPtr pPictFormat,
+ CARD16 width,
+ CARD16 height)
+{
+ PixmapPtr pPixmap;
+ PicturePtr pPicture;
+ GCPtr pGC;
+ int error;
+ xRectangle rect;
+
+ if (width > 32767 || height > 32767)
+ return 0;
+
+ if (!pPictFormat)
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ if (!pPictFormat)
+ return 0;
+ }
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ pPictFormat->depth, 0);
+ if (!pPixmap)
+ return 0;
+ pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
+ if (!pGC)
+ {
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return 0;
+ }
+ ValidateGC (&pPixmap->drawable, pGC);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ uxa_check_poly_fill_rect (&pPixmap->drawable, pGC, 1, &rect);
+ FreeScratchGC (pGC);
+ pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
+ 0, 0, serverClient, &error);
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return pPicture;
+}
+
+/**
+ * uxa_trapezoids is essentially a copy of miTrapezoids that uses
+ * uxa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to RasterizeTrapezoid won't be accelerated however, which
+ * forces the pixmap to be moved out again.
+ *
+ * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect
+ * to initialize the contents.
+ */
+void
+uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntrap, xTrapezoid *traps)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+ BoxRec bounds;
+ Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
+
+ if (maskFormat || direct) {
+ miTrapezoidBounds (ntrap, traps, &bounds);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return;
+ }
+
+ /*
+ * Check for solid alpha add
+ */
+ if (direct)
+ {
+ DrawablePtr pDraw = pDst->pDrawable;
+ PixmapPtr pixmap = uxa_get_drawable_pixmap (pDraw);
+ int xoff, yoff;
+
+ uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
+
+ xoff += pDraw->x;
+ yoff += pDraw->y;
+
+ uxa_prepare_access(pDraw, UXA_PREPARE_DEST);
+
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
+
+ uxa_finish_access(pDraw, UXA_PREPARE_DEST);
+ }
+ else if (maskFormat)
+ {
+ PicturePtr pPicture;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+
+ xDst = traps[0].left.p1.x >> 16;
+ yDst = traps[0].left.p1.y >> 16;
+
+ pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ if (!pPicture)
+ return;
+
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pPicture, traps,
+ -bounds.x1, -bounds.y1);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+
+ xRel = bounds.x1 + xSrc - xDst;
+ yRel = bounds.y1 + ySrc - yDst;
+ CompositePicture (op, pSrc, pPicture, pDst,
+ xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ FreePicture (pPicture, 0);
+ }
+ else
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ for (; ntrap; ntrap--, traps++)
+ uxa_trapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
+ }
+}
+
+/**
+ * uxa_triangles is essentially a copy of miTriangles that uses
+ * uxa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to AddTriangles won't be accelerated however, which forces the pixmap
+ * to be moved out again.
+ *
+ * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect
+ * to initialize the contents.
+ */
+void
+uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntri, xTriangle *tris)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+ BoxRec bounds;
+ Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
+
+ if (maskFormat || direct) {
+ miTriangleBounds (ntri, tris, &bounds);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return;
+ }
+
+ /*
+ * Check for solid alpha add
+ */
+ if (direct)
+ {
+ DrawablePtr pDraw = pDst->pDrawable;
+ uxa_prepare_access(pDraw, UXA_PREPARE_DEST);
+ (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+ uxa_finish_access(pDraw, UXA_PREPARE_DEST);
+ }
+ else if (maskFormat)
+ {
+ PicturePtr pPicture;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+
+ xDst = tris[0].p1.x >> 16;
+ yDst = tris[0].p1.y >> 16;
+
+ pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ if (!pPicture)
+ return;
+
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+
+ xRel = bounds.x1 + xSrc - xDst;
+ yRel = bounds.y1 + ySrc - yDst;
+ CompositePicture (op, pSrc, pPicture, pDst,
+ xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+ FreePicture (pPicture, 0);
+ }
+ else
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+
+ for (; ntri; ntri--, tris++)
+ uxa_triangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
+ }
+}
diff --git a/uxa/uxa-unaccel.c b/uxa/uxa-unaccel.c
new file mode 100644
index 00000000..27194208
--- /dev/null
+++ b/uxa/uxa-unaccel.c
@@ -0,0 +1,370 @@
+/*
+ *
+ * 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 "uxa-priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#endif
+
+/*
+ * These functions wrap the low-level fb rendering functions and
+ * synchronize framebuffer/accelerated drawing by stalling until
+ * the accelerator is idle
+ */
+
+/**
+ * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
+ * current fill style.
+ *
+ * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
+ * 1bpp and never in fb, so we don't worry about them.
+ * We should worry about them for completeness sake and going forward.
+ */
+void
+uxa_prepare_access_gc(GCPtr pGC)
+{
+ if (pGC->stipple)
+ uxa_prepare_access(&pGC->stipple->drawable, UXA_PREPARE_MASK);
+ if (pGC->fillStyle == FillTiled)
+ uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+/**
+ * Finishes access to the tile in the GC, if used.
+ */
+void
+uxa_finish_access_gc(GCPtr pGC)
+{
+ if (pGC->fillStyle == FillTiled)
+ uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_MASK);
+ if (pGC->stipple)
+ uxa_finish_access(&pGC->stipple->drawable, UXA_PREPARE_SRC);
+}
+
+#if DEBUG_TRACE_FALL
+char
+uxa_drawable_location(DrawablePtr pDrawable)
+{
+ return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm';
+}
+#endif /* DEBUG_TRACE_FALL */
+
+void
+uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+RegionPtr
+uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+ RegionPtr ret;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc), uxa_drawable_location(pDst)));
+ uxa_prepare_access (pDst, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrc, UXA_PREPARE_SRC);
+ ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+ uxa_finish_access (pSrc, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst, UXA_PREPARE_DEST);
+
+ return ret;
+}
+
+RegionPtr
+uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane)
+{
+ RegionPtr ret;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc), uxa_drawable_location(pDst)));
+ uxa_prepare_access (pDst, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrc, UXA_PREPARE_SRC);
+ ret = fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
+ bitPlane);
+ uxa_finish_access (pSrc, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst, UXA_PREPARE_DEST);
+
+ return ret;
+}
+
+void
+uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbPolyPoint (pDrawable, pGC, mode, npt, pptInit);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt)
+{
+ UXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
+ pDrawable, uxa_drawable_location(pDrawable),
+ pGC->lineWidth, mode, npt));
+
+ if (pGC->lineWidth == 0) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+}
+
+void
+uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit)
+{
+ UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->lineWidth, nsegInit));
+ if (pGC->lineWidth == 0) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+}
+
+void
+uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+
+ /* Disable this as fbPolyArc can call miZeroPolyArc which in turn
+ * can call accelerated functions, that as yet, haven't been notified
+ * with uxa_finish_access().
+ */
+#if 0
+ if (pGC->lineWidth == 0)
+ {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyArc (pDrawable, pGC, narcs, pArcs);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+#endif
+ miPolyArc (pDrawable, pGC, narcs, pArcs);
+}
+
+void
+uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyFillRect (pDrawable, pGC, nrect, prect);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->fillStyle, pGC->alu));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y)
+{
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
+ uxa_drawable_location(&pBitmap->drawable),
+ uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access (&pBitmap->drawable, UXA_PREPARE_SRC);
+ uxa_prepare_access_gc (pGC);
+ fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (&pBitmap->drawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_get_spans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart)
+{
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_SRC);
+ fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ uxa_finish_access (pDrawable, UXA_PREPARE_SRC);
+}
+
+void
+uxa_check_composite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ UXA_FALLBACK(("from picts %p/%p to pict %p\n",
+ pSrc, pMask, pDst));
+
+ uxa_prepare_access (pDst->pDrawable, UXA_PREPARE_DEST);
+ if (pSrc->pDrawable != NULL)
+ uxa_prepare_access (pSrc->pDrawable, UXA_PREPARE_SRC);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_prepare_access (pMask->pDrawable, UXA_PREPARE_MASK);
+ fbComposite (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc,
+ ySrc,
+ xMask,
+ yMask,
+ xDst,
+ yDst,
+ width,
+ height);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_finish_access (pMask->pDrawable, UXA_PREPARE_MASK);
+ if (pSrc->pDrawable != NULL)
+ uxa_finish_access (pSrc->pDrawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst->pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_add_traps (PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off,
+ int ntrap,
+ xTrap *traps)
+{
+ UXA_FALLBACK(("to pict %p (%c)\n",
+ uxa_drawable_location(pPicture->pDrawable)));
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ fbAddTraps (pPicture, x_off, y_off, ntrap, traps);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+}
+
+/**
+ * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
+ * that happen to be 1x1. Pixmap must be at least 8bpp.
+ *
+ * XXX This really belongs in fb, so it can be aware of tiling and etc.
+ */
+CARD32
+uxa_get_pixmap_first_pixel (PixmapPtr pPixmap)
+{
+ CARD32 pixel;
+ void *fb;
+
+ uxa_prepare_access (&pPixmap->drawable, UXA_PREPARE_SRC);
+ fb = pPixmap->devPrivate.ptr;
+
+ switch (pPixmap->drawable.bitsPerPixel) {
+ case 32:
+ pixel = *(CARD32 *)fb;
+ break;
+ case 16:
+ pixel = *(CARD16 *)fb;
+ break;
+ default:
+ pixel = *(CARD8 *)fb;
+ break;
+ }
+ uxa_finish_access(&pPixmap->drawable, UXA_PREPARE_SRC);
+
+ return pixel;
+}
diff --git a/uxa/uxa.c b/uxa/uxa.c
new file mode 100644
index 00000000..9745f8bb
--- /dev/null
+++ b/uxa/uxa.c
@@ -0,0 +1,573 @@
+/*
+ * 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.
+ */
+
+/** @file
+ * This file covers the initialization and teardown of UXA, and has various
+ * functions not responsible for performing rendering, pixmap migration, or
+ * memory management.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "uxa.h"
+
+DevPrivateKey uxa_screen_key = &uxa_screen_key;
+
+/**
+ * uxa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
+ *
+ * @param pDrawable the drawable being requested.
+ *
+ * This function returns the backing pixmap for a drawable, whether it is a
+ * redirected window, unredirected window, or already a pixmap. Note that
+ * coordinate translation is needed when drawing to the backing pixmap of a
+ * redirected window, and the translation coordinates are provided by calling
+ * uxa_get_drawable_pixmap() on the drawable.
+ */
+PixmapPtr
+uxa_get_drawable_pixmap(DrawablePtr pDrawable)
+{
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
+ else
+ return (PixmapPtr) pDrawable;
+}
+
+/**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+void
+uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+ int *xp, int *yp)
+{
+#ifdef COMPOSITE
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ *xp = -pPixmap->screen_x;
+ *yp = -pPixmap->screen_y;
+ return;
+ }
+#endif
+
+ *xp = 0;
+ *yp = 0;
+}
+
+/**
+ * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen
+ * memory, meaning that acceleration could probably be done to it, and that it
+ * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
+ * with the CPU.
+ *
+ * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
+ * deal with moving pixmaps in and out of system memory), UXA will give drivers
+ * pixmaps as arguments for which uxa_pixmap_is_offscreen() is TRUE.
+ *
+ * @return TRUE if the given drawable is in framebuffer memory.
+ */
+Bool
+uxa_pixmap_is_offscreen(PixmapPtr p)
+{
+ ScreenPtr pScreen = p->drawable.pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ if (uxa_screen->info->PixmapIsOffscreen)
+ return uxa_screen->info->PixmapIsOffscreen(p);
+
+ return FALSE;
+}
+
+/**
+ * uxa_drawable_is_offscreen() is a convenience wrapper for uxa_pixmap_is_offscreen().
+ */
+Bool
+uxa_drawable_is_offscreen (DrawablePtr pDrawable)
+{
+ return uxa_pixmap_is_offscreen (uxa_get_drawable_pixmap (pDrawable));
+}
+
+/**
+ * Returns the pixmap which backs a drawable, and the offsets to add to
+ * coordinates to make them address the same bits in the backing drawable.
+ */
+PixmapPtr
+uxa_get_offscreen_pixmap (DrawablePtr drawable, int *xp, int *yp)
+{
+ PixmapPtr pixmap = uxa_get_drawable_pixmap (drawable);
+
+ uxa_get_drawable_deltas (drawable, pixmap, xp, yp);
+
+ if (uxa_pixmap_is_offscreen (pixmap))
+ return pixmap;
+ else
+ return NULL;
+}
+
+
+
+/**
+ * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler.
+ *
+ * It deals with waiting for synchronization with the card, determining if
+ * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ */
+void
+uxa_prepare_access(DrawablePtr pDrawable, int index)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ Bool offscreen = uxa_pixmap_is_offscreen(pPixmap);
+
+ if (!offscreen)
+ return;
+
+ /* XXX should be pPixmap eventually */
+ uxa_wait_sync (pScreen);
+
+ if (uxa_screen->info->PrepareAccess)
+ (*uxa_screen->info->PrepareAccess) (pPixmap, index);
+}
+
+/**
+ * uxa_finish_access() is UXA's wrapper for the driver's FinishAccess() handler.
+ *
+ * It deals with calling the driver's FinishAccess() only if necessary.
+ */
+void
+uxa_finish_access(DrawablePtr pDrawable, int index)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+
+ if (uxa_screen->info->FinishAccess == NULL)
+ return;
+
+ if (!uxa_pixmap_is_offscreen (pPixmap))
+ return;
+
+ (*uxa_screen->info->FinishAccess) (pPixmap, index);
+}
+
+/**
+ * uxa_validate_gc() sets the ops to UXA's implementations, which may be
+ * accelerated or may sync the card and fall back to fb.
+ */
+static void
+uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+ /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
+ * Preempt fbValidateGC by doing its work and masking the change out, so
+ * that we can do the Prepare/FinishAccess.
+ */
+#ifdef FB_24_32BIT
+ if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
+ (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
+ fbGetRotatedPixmap(pGC) = 0;
+ }
+
+ if (pGC->fillStyle == FillTiled) {
+ PixmapPtr pOldTile, pNewTile;
+
+ pOldTile = pGC->tile.pixmap;
+ if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ {
+ pNewTile = fbGetRotatedPixmap(pGC);
+ if (!pNewTile ||
+ pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ {
+ if (pNewTile)
+ (*pGC->pScreen->DestroyPixmap) (pNewTile);
+ /* fb24_32ReformatTile will do direct access of a newly-
+ * allocated pixmap. This isn't a problem yet, since we don't
+ * put pixmaps in FB until at least one accelerated UXA op.
+ */
+ uxa_prepare_access(&pOldTile->drawable, UXA_PREPARE_SRC);
+ pNewTile = fb24_32ReformatTile (pOldTile,
+ pDrawable->bitsPerPixel);
+ uxa_finish_access(&pOldTile->drawable, UXA_PREPARE_SRC);
+ }
+ if (pNewTile)
+ {
+ fbGetRotatedPixmap(pGC) = pOldTile;
+ pGC->tile.pixmap = pNewTile;
+ changes |= GCTile;
+ }
+ }
+ }
+#endif
+ if (changes & GCTile) {
+ if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
+ pDrawable->bitsPerPixel))
+ {
+ uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+ fbPadPixmap (pGC->tile.pixmap);
+ uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+ }
+ /* Mask out the GCTile change notification, now that we've done FB's
+ * job for it.
+ */
+ changes &= ~GCTile;
+ }
+
+ uxa_prepare_access_gc(pGC);
+ fbValidateGC (pGC, changes, pDrawable);
+ uxa_finish_access_gc(pGC);
+
+ pGC->ops = (GCOps *) &uxa_ops;
+}
+
+static GCFuncs uxaGCFuncs = {
+ uxa_validate_gc,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+/**
+ * uxa_create_gc makes a new GC and hooks up its funcs handler, so that
+ * uxa_validate_gc() will get called.
+ */
+static int
+uxa_create_gc (GCPtr pGC)
+{
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ pGC->funcs = &uxaGCFuncs;
+
+ return TRUE;
+}
+
+void
+uxa_prepare_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+void
+uxa_finish_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_finish_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_finish_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+static Bool
+uxa_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+ Bool ret;
+
+ uxa_prepare_access_window(pWin);
+ ret = fbChangeWindowAttributes(pWin, mask);
+ uxa_finish_access_window(pWin);
+ return ret;
+}
+
+static RegionPtr
+uxa_bitmap_to_region(PixmapPtr pPix)
+{
+ RegionPtr ret;
+ uxa_prepare_access(&pPix->drawable, UXA_PREPARE_SRC);
+ ret = fbPixmapToRegion(pPix);
+ uxa_finish_access(&pPix->drawable, UXA_PREPARE_SRC);
+ return ret;
+}
+
+/**
+ * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's
+ * screen private, before calling down to the next CloseSccreen.
+ */
+static Bool
+uxa_close_screen(int i, ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+ uxa_glyphs_fini(pScreen);
+
+ pScreen->CreateGC = uxa_screen->SavedCreateGC;
+ pScreen->CloseScreen = uxa_screen->SavedCloseScreen;
+ pScreen->GetImage = uxa_screen->SavedGetImage;
+ pScreen->GetSpans = uxa_screen->SavedGetSpans;
+ pScreen->CreatePixmap = uxa_screen->SavedCreatePixmap;
+ pScreen->DestroyPixmap = uxa_screen->SavedDestroyPixmap;
+ pScreen->CopyWindow = uxa_screen->SavedCopyWindow;
+ pScreen->ChangeWindowAttributes = uxa_screen->SavedChangeWindowAttributes;
+ pScreen->BitmapToRegion = uxa_screen->SavedBitmapToRegion;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = uxa_screen->SavedComposite;
+ ps->Glyphs = uxa_screen->SavedGlyphs;
+ ps->Trapezoids = uxa_screen->SavedTrapezoids;
+ ps->AddTraps = uxa_screen->SavedAddTraps;
+ ps->Triangles = uxa_screen->SavedTriangles;
+ }
+#endif
+
+ xfree (uxa_screen);
+
+ return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+/**
+ * This function allocates a driver structure for UXA drivers to fill in. By
+ * having UXA allocate the structure, the driver structure can be extended
+ * without breaking ABI between UXA and the drivers. The driver's
+ * responsibility is to check beforehand that the UXA module has a matching
+ * major number and sufficient minor. Drivers are responsible for freeing the
+ * driver structure using xfree().
+ *
+ * @return a newly allocated, zero-filled driver structure
+ */
+uxa_driver_t *
+uxa_driver_alloc(void)
+{
+ return xcalloc(1, sizeof(uxa_driver_t));
+}
+
+/**
+ * @param pScreen screen being initialized
+ * @param pScreenInfo UXA driver record
+ *
+ * uxa_driver_init sets up UXA given a driver record filled in by the driver.
+ * pScreenInfo should have been allocated by uxa_driver_alloc(). See the
+ * comments in _UxaDriver for what must be filled in and what is optional.
+ *
+ * @return TRUE if UXA was successfully initialized.
+ */
+Bool
+uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver)
+{
+ uxa_screen_t *uxa_screen;
+#ifdef RENDER
+ PictureScreenPtr ps;
+#endif
+
+ if (!uxa_driver)
+ return FALSE;
+
+ if (uxa_driver->uxa_major != UXA_VERSION_MAJOR ||
+ uxa_driver->uxa_minor > UXA_VERSION_MINOR)
+ {
+ LogMessage(X_ERROR, "UXA(%d): driver's UXA version requirements "
+ "(%d.%d) are incompatible with UXA version (%d.%d)\n",
+ screen->myNum,
+ uxa_driver->uxa_major, uxa_driver->uxa_minor,
+ UXA_VERSION_MAJOR, UXA_VERSION_MINOR);
+ return FALSE;
+ }
+
+ if (!uxa_driver->PrepareSolid) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareSolid must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->PrepareCopy) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareCopy must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->WaitMarker) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::WaitMarker must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ /* If the driver doesn't set any max pitch values, we'll just assume
+ * that there's a limitation by pixels, and that it's the same as
+ * maxX.
+ *
+ * We want maxPitchPixels or maxPitchBytes to be set so we can check
+ * pixmaps against the max pitch in uxaCreatePixmap() -- it matters
+ * whether a pixmap is rejected because of its pitch or
+ * because of its width.
+ */
+ if (!uxa_driver->maxPitchPixels && !uxa_driver->maxPitchBytes)
+ {
+ uxa_driver->maxPitchPixels = uxa_driver->maxX;
+ }
+
+#ifdef RENDER
+ ps = GetPictureScreenIfSet(screen);
+#endif
+
+ uxa_screen = xcalloc (sizeof (uxa_screen_t), 1);
+
+ if (!uxa_screen) {
+ LogMessage(X_WARNING, "UXA(%d): Failed to allocate screen private\n",
+ screen->myNum);
+ return FALSE;
+ }
+
+ uxa_screen->info = uxa_driver;
+
+ dixSetPrivate(&screen->devPrivates, uxa_screen_key, uxa_screen);
+
+// exaDDXDriverInit(screen);
+
+ /*
+ * Replace various fb screen functions
+ */
+ uxa_screen->SavedCloseScreen = screen->CloseScreen;
+ screen->CloseScreen = uxa_close_screen;
+
+ uxa_screen->SavedCreateGC = screen->CreateGC;
+ screen->CreateGC = uxa_create_gc;
+
+ uxa_screen->SavedGetImage = screen->GetImage;
+ screen->GetImage = uxa_get_image;
+
+ uxa_screen->SavedGetSpans = screen->GetSpans;
+ screen->GetSpans = uxa_check_get_spans;
+
+ uxa_screen->SavedCopyWindow = screen->CopyWindow;
+ screen->CopyWindow = uxa_copy_window;
+
+ uxa_screen->SavedChangeWindowAttributes = screen->ChangeWindowAttributes;
+ screen->ChangeWindowAttributes = uxa_change_window_attributes;
+
+ uxa_screen->SavedBitmapToRegion = screen->BitmapToRegion;
+ screen->BitmapToRegion = uxa_bitmap_to_region;
+
+#ifdef RENDER
+ if (ps) {
+ uxa_screen->SavedComposite = ps->Composite;
+ ps->Composite = uxa_composite;
+
+ uxa_screen->SavedGlyphs = ps->Glyphs;
+ ps->Glyphs = uxa_glyphs;
+
+ uxa_screen->SavedTriangles = ps->Triangles;
+ ps->Triangles = uxa_triangles;
+
+ uxa_screen->SavedTrapezoids = ps->Trapezoids;
+ ps->Trapezoids = uxa_trapezoids;
+
+ uxa_screen->SavedAddTraps = ps->AddTraps;
+ ps->AddTraps = uxa_check_add_traps;
+ }
+#endif
+
+#ifdef MITSHM
+ /* Re-register with the MI funcs, which don't allow shared pixmaps.
+ * Shared pixmaps are almost always a performance loss for us, but this
+ * still allows for SHM PutImage.
+ */
+ ShmRegisterFuncs(screen, &uxa_shm_funcs);
+#endif
+
+ uxa_glyphs_init(screen);
+
+ LogMessage(X_INFO, "UXA(%d): Driver registered support for the following"
+ " operations:\n", screen->myNum);
+ assert(uxa_driver->PrepareSolid != NULL);
+ LogMessage(X_INFO, " Solid\n");
+ assert(uxa_driver->PrepareCopy != NULL);
+ LogMessage(X_INFO, " Copy\n");
+ if (uxa_driver->PrepareComposite != NULL) {
+ LogMessage(X_INFO, " Composite (RENDER acceleration)\n");
+ }
+ if (uxa_driver->UploadToScreen != NULL) {
+ LogMessage(X_INFO, " UploadToScreen\n");
+ }
+ if (uxa_driver->DownloadFromScreen != NULL) {
+ LogMessage(X_INFO, " DownloadFromScreen\n");
+ }
+
+ return TRUE;
+}
+
+/**
+ * uxa_driver_fini tears down UXA on a given screen.
+ *
+ * @param pScreen screen being torn down.
+ */
+void
+uxa_driver_fini (ScreenPtr pScreen)
+{
+ /*right now does nothing*/
+}
+
+/**
+ * uxa_mark_sync() should be called after any asynchronous drawing by the hardware.
+ *
+ * @param pScreen screen which drawing occurred on
+ *
+ * uxa_mark_sync() sets a flag to indicate that some asynchronous drawing has
+ * happened and a WaitSync() will be necessary before relying on the contents of
+ * offscreen memory from the CPU's perspective. It also calls an optional
+ * driver MarkSync() callback, the return value of which may be used to do partial
+ * synchronization with the hardware in the future.
+ */
+void uxa_mark_sync(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ uxa_screen->info->needsSync = TRUE;
+ if (uxa_screen->info->MarkSync != NULL) {
+ uxa_screen->info->lastMarker = (*uxa_screen->info->MarkSync)(pScreen);
+ }
+}
+
+/**
+ * uxa_wait_sync() ensures that all drawing has been completed.
+ *
+ * @param pScreen screen being synchronized.
+ *
+ * Calls down into the driver to ensure that all previous drawing has completed.
+ * It should always be called before relying on the framebuffer contents
+ * reflecting previous drawing, from a CPU perspective.
+ */
+void uxa_wait_sync(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ if (uxa_screen->info->needsSync && !uxa_screen->swappedOut) {
+ (*uxa_screen->info->WaitMarker)(pScreen, uxa_screen->info->lastMarker);
+ uxa_screen->info->needsSync = FALSE;
+ }
+}
diff --git a/uxa/uxa.h b/uxa/uxa.h
new file mode 100644
index 00000000..57e84f37
--- /dev/null
+++ b/uxa/uxa.h
@@ -0,0 +1,671 @@
+/*
+ * Copyright © 2000, 2008 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.
+ */
+
+/** @file
+ * UXA - the unified memory acceleration architecture.
+ *
+ * This is the header containing the public API of UXA for uxa drivers.
+ */
+
+#ifndef UXA_H
+#define UXA_H
+
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "picturestr.h"
+#include "fb.h"
+
+#define UXA_VERSION_MAJOR 1
+#define UXA_VERSION_MINOR 0
+#define UXA_VERSION_RELEASE 0
+
+/**
+ * The UxaDriver structure is allocated through uxa_driver_alloc(), and then
+ * fllled in by drivers.
+ */
+typedef struct _UxaDriver {
+ /**
+ * uxa_major and uxa_minor should be set by the driver to the version of
+ * UXA which the driver was compiled for (or configures itself at runtime
+ * to support). This allows UXA to extend the structure for new features
+ * without breaking ABI for drivers compiled against older versions.
+ */
+ int uxa_major, uxa_minor;
+
+ /**
+ * The flags field is bitfield of boolean values controlling UXA's behavior.
+ *
+ * The flags include UXA_TWO_BITBLT_DIRECTIONS.
+ */
+ int flags;
+
+ /** @{ */
+ /**
+ * maxX controls the X coordinate limitation for rendering from the card.
+ * The driver should never receive a request for rendering beyond maxX
+ * in the X direction from the origin of a pixmap.
+ */
+ int maxX;
+
+ /**
+ * maxY controls the Y coordinate limitation for rendering from the card.
+ * The driver should never receive a request for rendering beyond maxY
+ * in the Y direction from the origin of a pixmap.
+ */
+ int maxY;
+ /** @} */
+
+ /* private */
+ Bool needsSync;
+ int lastMarker;
+
+ /** @name Solid
+ * @{
+ */
+ /**
+ * PrepareSolid() sets up the driver for doing a solid fill.
+ * @param pPixmap Destination pixmap
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ * @param fg "foreground" color for the fill
+ *
+ * This call should set up the driver for doing a series of solid fills
+ * through the Solid() call. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls
+ * which bits of the destination should be affected, and will only represent
+ * the bits up to the depth of pPixmap. The fg is the pixel value of the
+ * foreground color referred to in ROP descriptions.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareSolid() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*PrepareSolid) (PixmapPtr pPixmap,
+ int alu,
+ Pixel planemask,
+ Pixel fg);
+
+ /**
+ * Solid() performs a solid fill set up in the last PrepareSolid() call.
+ *
+ * @param pPixmap destination pixmap
+ * @param x1 left coordinate
+ * @param y1 top coordinate
+ * @param x2 right coordinate
+ * @param y2 bottom coordinate
+ *
+ * Performs the fill set up by the last PrepareSolid() call, covering the
+ * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
+ * in the coordinate space of the destination pixmap, so the driver will
+ * need to set up the hardware's offset and pitch for the destination
+ * coordinates according to the pixmap's offset and pitch within
+ * framebuffer.
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+ void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
+
+ /**
+ * DoneSolid() finishes a set of solid fills.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneSolid() call is called at the end of a series of consecutive
+ * Solid() calls following a successful PrepareSolid(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareSolid().
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+ void (*DoneSolid) (PixmapPtr pPixmap);
+ /** @} */
+
+ /** @name Copy
+ * @{
+ */
+ /**
+ * PrepareCopy() sets up the driver for doing a copy within video
+ * memory.
+ *
+ * @param pSrcPixmap source pixmap
+ * @param pDstPixmap destination pixmap
+ * @param dx X copy direction
+ * @param dy Y copy direction
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ *
+ * This call should set up the driver for doing a series of copies from the
+ * the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
+ * hardware should do the copy from the left to the right, and dy will be
+ * positive if the copy should be done from the top to the bottom. This
+ * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
+ * If your hardware can only support blits that are (left to right, top to
+ * bottom) or (right to left, bottom to top), then you should set
+ * #UXA_TWO_BITBLT_DIRECTIONS, and UXA will break down Copy operations to
+ * ones that meet those requirements. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls which
+ * bits of the destination should be affected, and will only represent the
+ * bits up to the depth of pPixmap.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareCopy() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ int dx,
+ int dy,
+ int alu,
+ Pixel planemask);
+
+ /**
+ * Copy() performs a copy set up in the last PrepareCopy call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied.
+ *
+ * Performs the copy set up by the last PrepareCopy() call, copying the
+ * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
+ * pixmap to the same-sized rectangle at (dstX, dstY) in the destination
+ * pixmap. Those rectangles may overlap in memory, if
+ * pSrcPixmap == pDstPixmap. Note that this call does not receive the
+ * pSrcPixmap as an argument -- if it's needed in this function, it should
+ * be stored in the driver private during PrepareCopy(). As with Solid(),
+ * the coordinates are in the coordinate space of each pixmap, so the driver
+ * will need to set up source and destination pitches and offsets from those
+ * pixmaps, probably using uxaGetPixmapOffset() and uxa_get_pixmap_pitch().
+ *
+ * This call is required if PrepareCopy ever succeeds.
+ */
+ void (*Copy) (PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * DoneCopy() finishes a set of copies.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneCopy() call is called at the end of a series of consecutive
+ * Copy() calls following a successful PrepareCopy(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareCopy().
+ *
+ * This call is required if PrepareCopy() ever succeeds.
+ */
+ void (*DoneCopy) (PixmapPtr pDstPixmap);
+ /** @} */
+
+ /** @name Composite
+ * @{
+ */
+ /**
+ * CheckComposite() checks to see if a composite operation could be
+ * accelerated.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ *
+ * The CheckComposite() call checks if the driver could handle acceleration
+ * of op with the given source, mask, and destination pictures. This allows
+ * drivers to check source and destination formats, supported operations,
+ * transformations, and component alpha state, and send operations it can't
+ * support to software rendering early on. This avoids costly pixmap
+ * migration to the wrong places when the driver can't accelerate
+ * operations. Note that because migration hasn't happened, the driver
+ * can't know during CheckComposite() what the offsets and pitches of the
+ * pixmaps are going to be.
+ *
+ * See PrepareComposite() for more details on likely issues that drivers
+ * will have in accelerating Composite operations.
+ *
+ * The CheckComposite() call is recommended if PrepareComposite() is
+ * implemented, but is not required.
+ */
+ Bool (*CheckComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture);
+
+ /**
+ * PrepareComposite() sets up the driver for doing a Composite operation
+ * described in the Render extension protocol spec.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ * @param pSrc source pixmap
+ * @param pMask mask pixmap
+ * @param pDst destination pixmap
+ *
+ * This call should set up the driver for doing a series of Composite
+ * operations, as described in the Render protocol spec, with the given
+ * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
+ * pDst are the pixmaps containing the pixel data, and should be used for
+ * setting the offset and pitch used for the coordinate spaces for each of
+ * the Pictures.
+ *
+ * Notes on interpreting Picture structures:
+ * - The Picture structures will always have a valid pDrawable.
+ * - The Picture structures will never have alphaMap set.
+ * - The mask Picture (and therefore pMask) may be NULL, in which case the
+ * operation is simply src OP dst instead of src IN mask OP dst, and
+ * mask coordinates should be ignored.
+ * - pMarkPicture may have componentAlpha set, which greatly changes
+ * the behavior of the Composite operation. componentAlpha has no effect
+ * when set on pSrcPicture or pDstPicture.
+ * - The source and mask Pictures may have a transformation set
+ * (Picture->transform != NULL), which means that the source coordinates
+ * should be transformed by that transformation, resulting in scaling,
+ * rotation, etc. The PictureTransformPoint() call can transform
+ * coordinates for you. Transforms have no effect on Pictures when used
+ * as a destination.
+ * - The source and mask pictures may have a filter set. PictFilterNearest
+ * and PictFilterBilinear are defined in the Render protocol, but others
+ * may be encountered, and must be handled correctly (usually by
+ * PrepareComposite failing, and falling back to software). Filters have
+ * no effect on Pictures when used as a destination.
+ * - The source and mask Pictures may have repeating set, which must be
+ * respected. Many chipsets will be unable to support repeating on
+ * pixmaps that have a width or height that is not a power of two.
+ *
+ * If your hardware can't support source pictures (textures) with
+ * non-power-of-two pitches, you should set #UXA_OFFSCREEN_ALIGN_POT.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareComposite() call is not required. However, it is highly
+ * recommended for performance of antialiased font rendering and performance
+ * of cairo applications. Failure results in a fallback to software
+ * rendering.
+ */
+ Bool (*PrepareComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask,
+ PixmapPtr pDst);
+
+ /**
+ * Composite() performs a Composite operation set up in the last
+ * PrepareComposite() call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param maskX source X coordinate
+ * @param maskY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width destination rectangle width
+ * @param height destination rectangle height
+ *
+ * Performs the Composite operation set up by the last PrepareComposite()
+ * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
+ * in the destination Pixmap. Note that if a transformation was set on
+ * the source or mask Pictures, the source rectangles may not be the same
+ * size as the destination rectangles and filtering. Getting the coordinate
+ * transformation right at the subpixel level can be tricky, and rendercheck
+ * can test this for you.
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+ void (*Composite) (PixmapPtr pDst,
+ int srcX,
+ int srcY,
+ int maskX,
+ int maskY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * DoneComposite() finishes a set of Composite operations.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneComposite() call is called at the end of a series of consecutive
+ * Composite() calls following a successful PrepareComposite(). This allows
+ * drivers to finish up emitting drawing commands that were buffered, or
+ * clean up state from PrepareComposite().
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+ void (*DoneComposite) (PixmapPtr pDst);
+ /** @} */
+
+ /**
+ * UploadToScreen() loads a rectangle of data from src into pDst.
+ *
+ * @param pDst destination pixmap
+ * @param x destination X coordinate.
+ * @param y destination Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied
+ * @param src pointer to the beginning of the source data
+ * @param src_pitch pitch (in bytes) of the lines of source data.
+ *
+ * UploadToScreen() copies data in system memory beginning at src (with
+ * pitch src_pitch) into the destination pixmap from (x, y) to
+ * (x + width, y + height). This is typically done with hostdata uploads,
+ * where the CPU sets up a blit command on the hardware with instructions
+ * that the blit data will be fed through some sort of aperture on the card.
+ *
+ * If UploadToScreen() is performed asynchronously, it is up to the driver
+ * to call uxa_mark_sync(). This is in contrast to most other acceleration
+ * calls in UXA.
+ *
+ * UploadToScreen() can aid in pixmap migration, but is most important for
+ * the performance of uxa_glyphs() (antialiased font drawing) by allowing
+ * pipelining of data uploads, avoiding a sync of the card after each glyph.
+ *
+ * @return TRUE if the driver successfully uploaded the data. FALSE
+ * indicates that UXA should fall back to doing the upload in software.
+ *
+ * UploadToScreen() is not required, but is recommended if Composite
+ * acceleration is supported.
+ */
+ Bool (*UploadToScreen) (PixmapPtr pDst,
+ int x,
+ int y,
+ int w,
+ int h,
+ char *src,
+ int src_pitch);
+
+ /**
+ * UploadToScratch() is used to upload a pixmap to a scratch area for
+ * acceleration.
+ *
+ * @param pSrc source pixmap in host memory
+ * @param pDst fake, scratch pixmap to be set up in offscreen memory.
+ *
+ * The UploadToScratch() call was added to support Xati before Xati had
+ * support for hostdata uploads and before uxa_glyphs() was written. It
+ * behaves incorrectly (uses an invalid pixmap as pDst),
+ * and UploadToScreen() should be implemented instead.
+ *
+ * Drivers implementing UploadToScratch() had to set up space (likely in a
+ * statically allocated area) in offscreen memory, copy pSrc to that
+ * scratch area, and adust pDst->devKind for the pitch and
+ * pDst->devPrivate.ptr for the pointer to that scratch area. The driver
+ * was responsible for syncing (as it was implemented using memcpy() in
+ * Xati), and only the data from the last UploadToScratch() was guaranteed
+ * to be valid at any given time.
+ *
+ * UploadToScratch() should not be implemented by drivers, and will likely
+ * be removed in a future version of UXA.
+ */
+ Bool (*UploadToScratch) (PixmapPtr pSrc,
+ PixmapPtr pDst);
+
+ /**
+ * DownloadFromScreen() loads a rectangle of data from pSrc into dst
+ *
+ * @param pSrc source pixmap
+ * @param x source X coordinate.
+ * @param y source Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied
+ * @param dst pointer to the beginning of the destination data
+ * @param dst_pitch pitch (in bytes) of the lines of destination data.
+ *
+ * DownloadFromScreen() copies data from offscreen memory in pSrc from
+ * (x, y) to (x + width, y + height), to system memory starting at
+ * dst (with pitch dst_pitch). This would usually be done
+ * using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
+ * and then synchronously reading from AGP. Because the implementation
+ * might be synchronous, UXA leaves it up to the driver to call
+ * uxa_mark_sync() if DownloadFromScreen() was asynchronous. This is in
+ * contrast to most other acceleration calls in UXA.
+ *
+ * DownloadFromScreen() can aid in the largest bottleneck in pixmap
+ * migration, which is the read from framebuffer when evicting pixmaps from
+ * framebuffer memory. Thus, it is highly recommended, even though
+ * implementations are typically complicated.
+ *
+ * @return TRUE if the driver successfully downloaded the data. FALSE
+ * indicates that UXA should fall back to doing the download in software.
+ *
+ * DownloadFromScreen() is not required, but is highly recommended.
+ */
+ Bool (*DownloadFromScreen)(PixmapPtr pSrc,
+ int x, int y,
+ int w, int h,
+ char *dst, int dst_pitch);
+
+ /**
+ * MarkSync() requests that the driver mark a synchronization point,
+ * returning an driver-defined integer marker which could be requested for
+ * synchronization to later in WaitMarker(). This might be used in the
+ * future to avoid waiting for full hardware stalls before accessing pixmap
+ * data with the CPU, but is not important in the current incarnation of
+ * UXA.
+ *
+ * Note that drivers should call uxa_mark_sync() when they have done some
+ * acceleration, rather than their own MarkSync() handler, as otherwise UXA
+ * will be unaware of the driver's acceleration and not sync to it during
+ * fallbacks.
+ *
+ * MarkSync() is optional.
+ */
+ int (*MarkSync) (ScreenPtr pScreen);
+
+ /**
+ * WaitMarker() waits for all rendering before the given marker to have
+ * completed. If the driver does not implement MarkSync(), marker is
+ * meaningless, and all rendering by the hardware should be completed before
+ * WaitMarker() returns.
+ *
+ * Note that drivers should call uxa_wait_sync() to wait for all acceleration
+ * to finish, as otherwise UXA will be unaware of the driver having
+ * synchronized, resulting in excessive WaitMarker() calls.
+ *
+ * WaitMarker() is required of all drivers.
+ */
+ void (*WaitMarker) (ScreenPtr pScreen, int marker);
+
+ /** @{ */
+ /**
+ * PrepareAccess() is called before CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * PrepareAccess() will be called before CPU access to an offscreen pixmap.
+ * This can be used to set up hardware surfaces for byteswapping or
+ * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
+ * making CPU access use a different aperture.
+ *
+ * The index is one of #UXA_PREPARE_DEST, #UXA_PREPARE_SRC, or
+ * #UXA_PREPARE_MASK, indicating which pixmap is in question. Since only up
+ * to three pixmaps will have PrepareAccess() called on them per operation,
+ * drivers can have a small, statically-allocated space to maintain state
+ * for PrepareAccess() and FinishAccess() in. Note that the same pixmap may
+ * have PrepareAccess() called on it more than once, for uxample when doing
+ * a copy within the same pixmap (so it gets PrepareAccess as()
+ * #UXA_PREPARE_DEST and then as #UXA_PREPARE_SRC).
+ *
+ * PrepareAccess() may fail. An uxample might be the case of hardware that
+ * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
+ * fails, UXA will migrate the pixmap to system memory.
+ * DownloadFromScreen() must be implemented and must not fail if a driver
+ * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
+ * pPix is the visible screen, because the visible screen can not be
+ * migrated.
+ *
+ * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
+ * drawing.
+ * @return FALSE if PrepareAccess() is unsuccessful and UXA should use
+ * DownloadFromScreen() to migate the pixmap out.
+ */
+ Bool (*PrepareAccess)(PixmapPtr pPix, int index);
+
+ /**
+ * FinishAccess() is called after CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * FinishAccess() will be called after finishing CPU access of an offscreen
+ * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
+ * called if PrepareAccess() failed and the pixmap was migrated out.
+ */
+ void (*FinishAccess)(PixmapPtr pPix, int index);
+
+ /**
+ * PixmapIsOffscreen() is an optional driver replacement to
+ * uxa_pixmap_is_offscreen(). Set to NULL if you want the standard behaviour
+ * of uxa_pixmap_is_offscreen().
+ *
+ * @param pPix the pixmap
+ * @return TRUE if the given drawable is in framebuffer memory.
+ *
+ * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen
+ * memory, meaning that acceleration could probably be done to it, and that it
+ * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
+ * with the CPU.
+ *
+ *
+ */
+ Bool (*PixmapIsOffscreen)(PixmapPtr pPix);
+
+ /** @name PrepareAccess() and FinishAccess() indices
+ * @{
+ */
+ /**
+ * UXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
+ * read from.
+ */
+ #define UXA_PREPARE_DEST 0
+ /**
+ * UXA_PREPARE_SRC is the index for a pixmap that may be read from
+ */
+ #define UXA_PREPARE_SRC 1
+ /**
+ * UXA_PREPARE_SRC is the index for a second pixmap that may be read
+ * from.
+ */
+ #define UXA_PREPARE_MASK 2
+ /** @} */
+
+ /**
+ * maxPitchPixels controls the pitch limitation for rendering from
+ * the card.
+ * The driver should never receive a request for rendering a pixmap
+ * that has a pitch (in pixels) beyond maxPitchPixels.
+ *
+ * Setting this field is optional -- if your hardware doesn't have
+ * a pitch limitation in pixels, don't set this. If neither this value
+ * nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
+ * If set, it must not be smaller than maxX.
+ *
+ * @sa maxPitchBytes
+ */
+ int maxPitchPixels;
+
+ /**
+ * maxPitchBytes controls the pitch limitation for rendering from
+ * the card.
+ * The driver should never receive a request for rendering a pixmap
+ * that has a pitch (in bytes) beyond maxPitchBytes.
+ *
+ * Setting this field is optional -- if your hardware doesn't have
+ * a pitch limitation in bytes, don't set this.
+ * If set, it must not be smaller than maxX * 4.
+ * There's no default value for maxPitchBytes.
+ *
+ * @sa maxPitchPixels
+ */
+ int maxPitchBytes;
+
+ /** @} */
+} uxa_driver_t;
+
+/** @name UXA driver flags
+ * @{
+ */
+/**
+ * UXA_TWO_BITBLT_DIRECTIONS indicates to UXA that the driver can only
+ * support copies that are (left-to-right, top-to-bottom) or
+ * (right-to-left, bottom-to-top).
+ */
+#define UXA_TWO_BITBLT_DIRECTIONS (1 << 2)
+
+/** @} */
+
+uxa_driver_t *
+uxa_driver_alloc(void);
+
+Bool
+uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver);
+
+void
+uxa_driver_fini(ScreenPtr pScreen);
+
+void
+uxa_mark_sync(ScreenPtr pScreen);
+
+void
+uxa_wait_sync(ScreenPtr pScreen);
+
+void
+uxaEnableDisableFBAccess (int index, Bool enable);
+
+CARD32
+uxa_get_pixmap_first_pixel (PixmapPtr pPixmap);
+
+/**
+ * Returns TRUE if the given planemask covers all the significant bits in the
+ * pixel values for pDrawable.
+ */
+#define UXA_PM_IS_SOLID(_pDrawable, _pm) \
+ (((_pm) & FbFullMask((_pDrawable)->depth)) == \
+ FbFullMask((_pDrawable)->depth))
+
+#endif /* UXA_H */