summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann <ssp@redhat.com>2010-06-02 10:13:56 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2010-09-14 06:32:52 -0400
commit65d5ac5a0eecbf0ee3abdb6998ce5e615e05bb4e (patch)
treee004657c913933cfe4115d2d481f2ffbafae45b0
parente691e979b476f1ff9c6c93e12f6cea02dcb8c841 (diff)
Add a copy of UXA, but don't use it yet
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/uxa/Makefile.am17
-rw-r--r--src/uxa/uxa-accel.c1257
-rw-r--r--src/uxa/uxa-glyphs.c1172
-rw-r--r--src/uxa/uxa-priv.h426
-rw-r--r--src/uxa/uxa-render.c1957
-rw-r--r--src/uxa/uxa-unaccel.c430
-rw-r--r--src/uxa/uxa.c579
-rw-r--r--src/uxa/uxa.h583
10 files changed, 6424 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 844001e..e37a84d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,5 +82,6 @@ AC_SUBST([DRIVER_NAME])
AC_CONFIG_FILES([
Makefile
src/Makefile
+ src/uxa/Makefile
])
AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 14b68ec..fd1ba81 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,6 +25,8 @@
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+SUBDIRS=uxa
+
AM_CFLAGS = $(XORG_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS)
qxl_drv_la_LTLIBRARIES = qxl_drv.la
diff --git a/src/uxa/Makefile.am b/src/uxa/Makefile.am
new file mode 100644
index 0000000..c875b63
--- /dev/null
+++ b/src/uxa/Makefile.am
@@ -0,0 +1,17 @@
+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=""
+
+AM_CFLAGS = $(CWARNFLAGS) $(XORG_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/src/uxa/uxa-accel.c b/src/uxa/uxa-accel.c
new file mode 100644
index 0000000..e4dbfcc
--- /dev/null
+++ b/src/uxa/uxa-accel.c
@@ -0,0 +1,1257 @@
+/*
+ * 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"
+#include "mipict.h"
+
+static CARD32
+format_for_depth(int depth)
+{
+ switch (depth) {
+ case 1: return PICT_a1;
+ case 4: return PICT_a4;
+ case 8: return PICT_a8;
+ case 15: return PICT_x1r5g5b5;
+ case 16: return PICT_r5g6b5;
+ default:
+ case 24: return PICT_x8r8g8b8;
+ case 32: return PICT_a8r8g8b8;
+ }
+}
+
+static void
+uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr dst_pixmap, src_pixmap = NULL;
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+ xRenderColor color;
+ PictFormatPtr format;
+ PicturePtr dst, src;
+ int error;
+
+ if (uxa_screen->swappedOut || uxa_screen->force_fallback)
+ goto fallback;
+
+ if (pGC->fillStyle != FillSolid)
+ goto fallback;
+
+ dst_pixmap = uxa_get_offscreen_pixmap(pDrawable, &off_x, &off_y);
+ if (!dst_pixmap)
+ goto fallback;
+
+ if (pGC->alu != GXcopy || pGC->planemask != FB_ALLONES)
+ goto solid;
+
+ format = PictureMatchFormat(screen,
+ dst_pixmap->drawable.depth,
+ format_for_depth(dst_pixmap->drawable.depth));
+ dst = CreatePicture(0, &dst_pixmap->drawable, format, 0, 0, serverClient, &error);
+ if (!dst)
+ goto solid;
+
+ ValidatePicture(dst);
+
+ uxa_get_rgba_from_pixel(pGC->fgPixel,
+ &color.red,
+ &color.green,
+ &color.blue,
+ &color.alpha,
+ format_for_depth(dst_pixmap->drawable.depth));
+ src = CreateSolidPicture(0, &color, &error);
+ if (!src) {
+ FreePicture(dst, 0);
+ goto solid;
+ }
+
+ if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst, 0, 0)) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto solid;
+ }
+
+ if (!uxa_screen->info->check_composite_texture ||
+ !uxa_screen->info->check_composite_texture(screen, src)) {
+ PicturePtr solid;
+ int src_off_x, src_off_y;
+
+ solid = uxa_acquire_solid(screen, src->pSourcePict);
+ FreePicture(src, 0);
+
+ src = solid;
+ src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
+ &src_off_x, &src_off_y);
+ if (!src_pixmap) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto solid;
+ }
+ }
+
+ if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, dst_pixmap)) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto solid;
+ }
+
+ pextent = REGION_EXTENTS(pGC->screen, 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->composite(dst_pixmap,
+ 0, 0, 0, 0,
+ fullX1 + off_x,
+ fullY1 + off_y,
+ fullX2 - fullX1, 1);
+ } else {
+ pbox = REGION_RECTS(pClip);
+ while (nbox--) {
+ if (pbox->y1 > fullY1)
+ break;
+
+ if (pbox->y1 <= fullY1) {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+
+ if (partX2 > partX1) {
+ uxa_screen->info->composite(dst_pixmap,
+ 0, 0, 0, 0,
+ partX1 + off_x,
+ fullY1 + off_y,
+ partX2 - partX1, 1);
+ }
+ }
+ pbox++;
+ }
+ }
+ }
+
+ uxa_screen->info->done_composite(dst_pixmap);
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ return;
+
+solid:
+ if (uxa_screen->info->check_solid &&
+ !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask))
+ goto fallback;
+
+ if (!(*uxa_screen->info->prepare_solid) (dst_pixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ goto fallback;
+
+ pextent = REGION_EXTENTS(pGC->screen, 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) (dst_pixmap,
+ 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) (dst_pixmap,
+ partX1 + off_x,
+ fullY1 + off_y,
+ partX2 + off_x,
+ fullY1 + 1 + off_y);
+ }
+ }
+ pbox++;
+ }
+ }
+ }
+ (*uxa_screen->info->done_solid) (dst_pixmap);
+
+ return;
+
+fallback:
+ uxa_check_fill_spans(pDrawable, pGC, n, ppt, pwidth, fSorted);
+}
+
+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;
+ RegionPtr pClip;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int bpp = pDrawable->bitsPerPixel;
+
+ /* Don't bother with under 8bpp, XYPixmaps. */
+ if (format != ZPixmap || bpp < 8)
+ return FALSE;
+
+ if (uxa_screen->swappedOut || uxa_screen->force_fallback)
+ return FALSE;
+
+ if (!uxa_screen->info->put_image)
+ return FALSE;
+
+ /* Only accelerate copies: no rop or planemask. */
+ if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
+ return FALSE;
+
+ pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
+ if (!pPix)
+ 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->put_image(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 (!uxa_prepare_access(pDrawable, UXA_ACCESS_RW))
+ return FALSE;
+
+ 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);
+
+ uxa_finish_access(pDrawable);
+ }
+ }
+
+
+ return TRUE;
+}
+
+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)
+{
+ if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits,
+ PixmapBytePad(w, pDrawable->depth))) {
+ 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->done_copy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->prepare_copy)
+ (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->done_copy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->prepare_copy)
+ (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->done_copy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->prepare_copy)
+ (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->done_copy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->prepare_copy)
+ (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->done_copy(pDstPixmap);
+ 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)
+{
+ ScreenPtr screen = pDstDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ 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);
+ if (!pSrcPixmap || !pDstPixmap)
+ goto fallback;
+
+ if (uxa_screen->info->check_copy &&
+ !uxa_screen->info->check_copy(pSrcPixmap, pDstPixmap,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES))
+ goto fallback;
+
+ 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(pDstPixmap))
+ goto fallback;
+
+ if (uxa_pixmap_is_offscreen(pSrcPixmap)) {
+ if (!(*uxa_screen->info->prepare_copy) (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->done_copy) (pDstPixmap);
+ } else {
+ int stride, bpp;
+ char *src;
+
+ if (!uxa_screen->info->put_image)
+ goto fallback;
+
+ /* Don't bother with under 8bpp, XYPixmaps. */
+ bpp = pSrcPixmap->drawable.bitsPerPixel;
+ if (bpp != pDstDrawable->bitsPerPixel || bpp < 8)
+ goto fallback;
+
+ /* Only accelerate copies: no rop or planemask. */
+ if (pGC && (!UXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask) || pGC->alu != GXcopy))
+ goto fallback;
+
+ src = pSrcPixmap->devPrivate.ptr;
+ stride = pSrcPixmap->devKind;
+ bpp /= 8;
+ while (nbox--) {
+ if (!uxa_screen->info->put_image(pDstPixmap,
+ pbox->x1 + dst_off_x,
+ pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1,
+ (char *) src +
+ (pbox->y1 + dy + src_off_y) * stride +
+ (pbox->x1 + dx + src_off_x) * bpp,
+ stride))
+ goto fallback;
+
+ pbox++;
+ }
+ }
+
+ return;
+
+fallback:
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+ uxa_drawable_location(pSrcDrawable),
+ uxa_drawable_location(pDstDrawable)));
+ if (uxa_prepare_access(pDstDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(pSrcDrawable, UXA_ACCESS_RO)) {
+ fbCopyNtoN(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ dx, dy, reverse, upsidedown, bitplane,
+ closure);
+ uxa_finish_access(pSrcDrawable);
+ }
+ uxa_finish_access(pDstDrawable);
+ }
+}
+
+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 || uxa_screen->force_fallback) {
+ return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx,
+ dsty);
+ }
+
+ return miDoCopy(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);
+ if (!prect)
+ return;
+ 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));
+ if (!prect)
+ return;
+ 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);
+ if (!prect)
+ return;
+ 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;
+ 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;
+
+ if (uxa_screen->swappedOut || uxa_screen->force_fallback)
+ goto fallback;
+
+ pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+ if (!pPixmap)
+ 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_screen->info->check_solid &&
+ !uxa_screen->info->check_solid(pDrawable, pGC->alu, pGC->planemask)) {
+ goto fallback;
+ }
+
+ if (!(*uxa_screen->info->prepare_solid) (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->done_solid) (pPixmap);
+
+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
+
+ miCopyRegion(&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)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PixmapPtr pixmap;
+ int xoff, yoff;
+ int nbox;
+ BoxPtr pBox, extents;
+ Bool ret = FALSE;
+
+ pixmap = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
+ if (!pixmap)
+ return FALSE;
+
+ REGION_TRANSLATE(screen, pRegion, xoff, yoff);
+
+ nbox = REGION_NUM_RECTS(pRegion);
+ pBox = REGION_RECTS(pRegion);
+ extents = REGION_EXTENTS(screen, pRegion);
+
+ /* Using GEM, the relocation costs outweigh the advantages of the blitter */
+ if (nbox == 1 || (alu != GXcopy && alu != GXclear) || planemask != FB_ALLONES) {
+try_solid:
+ if (uxa_screen->info->check_solid &&
+ !uxa_screen->info->check_solid(&pixmap->drawable, alu, planemask))
+ goto err;
+
+ if (!uxa_screen->info->prepare_solid(pixmap, alu, planemask, pixel))
+ goto err;
+
+ while (nbox--) {
+ uxa_screen->info->solid(pixmap,
+ pBox->x1, pBox->y1,
+ pBox->x2, pBox->y2);
+ pBox++;
+ }
+
+ uxa_screen->info->done_solid(pixmap);
+ } else {
+ PicturePtr dst, src;
+ PixmapPtr src_pixmap = NULL;
+ xRenderColor color;
+ int error;
+
+ dst = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen,
+ pixmap->drawable.depth,
+ format_for_depth(pixmap->drawable.depth)),
+ 0, 0, serverClient, &error);
+ if (!dst)
+ goto err;
+
+ ValidatePicture(dst);
+
+ uxa_get_rgba_from_pixel(pixel,
+ &color.red,
+ &color.green,
+ &color.blue,
+ &color.alpha,
+ format_for_depth(pixmap->drawable.depth));
+ src = CreateSolidPicture(0, &color, &error);
+ if (!src) {
+ FreePicture(dst, 0);
+ goto err;
+ }
+
+ if (!uxa_screen->info->check_composite(PictOpSrc, src, NULL, dst,
+ extents->x2 - extents->x1,
+ extents->y2 - extents->y1)) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto try_solid;
+ }
+
+ if (!uxa_screen->info->check_composite_texture ||
+ !uxa_screen->info->check_composite_texture(screen, src)) {
+ PicturePtr solid;
+ int src_off_x, src_off_y;
+
+ solid = uxa_acquire_solid(screen, src->pSourcePict);
+ FreePicture(src, 0);
+
+ src = solid;
+ src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
+ &src_off_x, &src_off_y);
+ if (!src_pixmap) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto err;
+ }
+ }
+
+ if (!uxa_screen->info->prepare_composite(PictOpSrc, src, NULL, dst, src_pixmap, NULL, pixmap)) {
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ goto err;
+ }
+
+ while (nbox--) {
+ uxa_screen->info->composite(pixmap,
+ 0, 0, 0, 0,
+ pBox->x1,
+ pBox->y1,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+ pBox++;
+ }
+
+ uxa_screen->info->done_composite(pixmap);
+ FreePicture(src, 0);
+ FreePicture(dst, 0);
+ }
+
+ ret = TRUE;
+
+err:
+ REGION_TRANSLATE(screen, 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_offscreen_pixmap(pDrawable, &xoff, &yoff);
+ if (!pPixmap || !uxa_pixmap_is_offscreen(pTile))
+ goto out;
+
+ if (uxa_screen->info->check_copy &&
+ !uxa_screen->info->check_copy(pTile, pPixmap, alu, planemask))
+ return FALSE;
+
+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+ if ((*uxa_screen->info->prepare_copy) (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->done_copy) (pPixmap);
+
+ 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)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ 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 || uxa_screen->force_fallback)
+ goto fallback;
+
+ pPix = uxa_get_offscreen_pixmap(pDrawable, &xoff, &yoff);
+
+ if (pPix == NULL || uxa_screen->info->get_image == 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->get_image(pPix, pDrawable->x + x + xoff,
+ pDrawable->y + y + yoff, w, h, d,
+ PixmapBytePad(w, pDrawable->depth));
+ if (ok)
+ return;
+
+fallback:
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RO)) {
+ fbGetImage(pDrawable, x, y, w, h, format, planeMask, d);
+ uxa_finish_access(pDrawable);
+ }
+
+ return;
+}
diff --git a/src/uxa/uxa-glyphs.c b/src/uxa/uxa-glyphs.c
new file mode 100644
index 0000000..3ff504c
--- /dev/null
+++ b/src/uxa/uxa-glyphs.c
@@ -0,0 +1,1172 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ * Partly based on code 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 Intel not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Intel makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL
+ * 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 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: Chris Wilson <chris@chris-wilson.co.uk>
+ * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+
+#include "mipict.h"
+
+/* 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_SIZE 1024
+#define GLYPH_MIN_SIZE 8
+#define GLYPH_MAX_SIZE 64
+#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
+
+struct uxa_glyph {
+ uxa_glyph_cache_t *cache;
+ uint16_t x, y;
+ uint16_t size, pos;
+};
+
+static int uxa_glyph_index;
+
+static inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph)
+{
+ return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_index);
+}
+
+static inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv)
+{
+ dixSetPrivate(&glyph->devPrivates, &uxa_glyph_index, priv);
+}
+
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+
+static void uxa_unrealize_glyph_caches(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (cache->picture)
+ FreePicture(cache->picture, 0);
+
+ if (cache->glyphs)
+ xfree(cache->glyphs);
+ }
+}
+
+void uxa_glyphs_fini(ScreenPtr pScreen)
+{
+ uxa_unrealize_glyph_caches(pScreen);
+}
+
+/* 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)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ unsigned int formats[] = {
+ PIXMAN_a8,
+ PIXMAN_a8r8g8b8,
+ };
+ int i;
+
+ memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
+
+ for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+ PixmapPtr pixmap;
+ PicturePtr picture;
+ CARD32 component_alpha;
+ int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
+ int error;
+ PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]);
+ if (!pPictFormat)
+ goto bail;
+
+ /* Now allocate the pixmap and picture */
+ pixmap = pScreen->CreatePixmap(pScreen,
+ CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth,
+ 0 /* INTEL_CREATE_PIXMAP_TILING_X -- FIXME */);
+ if (!pixmap)
+ goto bail;
+ assert (uxa_pixmap_is_offscreen(pixmap));
+
+ component_alpha = NeedsComponent(pPictFormat->format);
+ picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
+ CPComponentAlpha, &component_alpha,
+ serverClient, &error);
+
+ pScreen->DestroyPixmap(pixmap);
+
+ if (!picture)
+ goto bail;
+
+ ValidatePicture(picture);
+
+ cache->picture = picture;
+ cache->glyphs = xcalloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
+ if (!cache->glyphs)
+ goto bail;
+
+ cache->evict = rand() % GLYPH_CACHE_SIZE;
+ }
+ assert(i == UXA_NUM_GLYPH_CACHE_FORMATS);
+
+ return TRUE;
+
+bail:
+ uxa_unrealize_glyph_caches(pScreen);
+ return FALSE;
+}
+
+
+Bool uxa_glyphs_init(ScreenPtr pScreen)
+{
+ if (!dixRequestPrivate(&uxa_glyph_index, 0))
+ return FALSE;
+
+ if (!uxa_realize_glyph_caches(pScreen))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* The most efficient thing to way to upload the glyph to the screen
+ * is to use CopyArea; uxa pixmaps are always offscreen.
+ */
+static void
+uxa_glyph_cache_upload_glyph(ScreenPtr screen,
+ uxa_glyph_cache_t * cache,
+ GlyphPtr glyph,
+ int x, int y)
+{
+ PicturePtr pGlyphPicture = GlyphPicture(glyph)[screen->myNum];
+ PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
+ PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
+ PixmapPtr scratch;
+ GCPtr gc;
+
+ gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
+ if (!gc)
+ return;
+
+ ValidateGC(&pCachePixmap->drawable, gc);
+
+ scratch = pGlyphPixmap;
+ /* Create a temporary bo to stream the updates to the cache */
+ if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
+ !uxa_pixmap_is_offscreen(scratch)) {
+ scratch = screen->CreatePixmap(screen,
+ glyph->info.width,
+ glyph->info.height,
+ pCachePixmap->drawable.depth,
+ UXA_CREATE_PIXMAP_FOR_MAP);
+ if (scratch) {
+ if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
+ PicturePtr picture;
+ int error;
+
+ picture = CreatePicture(0, &scratch->drawable,
+ PictureMatchFormat(screen,
+ pCachePixmap->drawable.depth,
+ cache->picture->format),
+ 0, NULL,
+ serverClient, &error);
+ if (picture) {
+ ValidatePicture(picture);
+ uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ glyph->info.width, glyph->info.height);
+ FreePicture(picture, 0);
+ }
+ } else {
+ uxa_copy_area(&pGlyphPixmap->drawable,
+ &scratch->drawable,
+ gc,
+ 0, 0,
+ glyph->info.width, glyph->info.height,
+ 0, 0);
+ }
+ } else {
+ scratch = pGlyphPixmap;
+ }
+ }
+
+ uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
+ 0, 0,
+ glyph->info.width, glyph->info.height,
+ x, y);
+
+ if (scratch != pGlyphPixmap)
+ screen->DestroyPixmap(scratch);
+
+ FreeScratchGC(gc);
+}
+
+void
+uxa_glyph_unrealize(ScreenPtr pScreen,
+ GlyphPtr pGlyph)
+{
+ struct uxa_glyph *priv;
+
+ priv = uxa_glyph_get_private(pGlyph);
+ if (priv == NULL)
+ return;
+
+ priv->cache->glyphs[priv->pos] = NULL;
+
+ uxa_glyph_set_private(pGlyph, NULL);
+ xfree(priv);
+}
+
+/* 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 x, y, n;
+
+ x1 = y1 = MAXSHORT;
+ x2 = y2 = MINSHORT;
+ x = y = 0;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+ int v;
+
+ v = x - glyph->info.x;
+ if (v < x1)
+ x1 = v;
+ v += glyph->info.width;
+ if (v > x2)
+ x2 = v;
+
+ v = y - glyph->info.y;
+ if (v < y1)
+ y1 = v;
+ v += glyph->info.height;
+ if (v > y2)
+ y2 = v;
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+
+ extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
+ extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
+ extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
+ extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
+}
+
+/**
+ * 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;
+ int x, y;
+ BoxRec extents;
+ Bool first = TRUE;
+
+ x = 0;
+ y = 0;
+ extents.x1 = 0;
+ extents.y1 = 0;
+ extents.x2 = 0;
+ extents.y2 = 0;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ GlyphPtr 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;
+}
+
+static void
+uxa_check_glyphs(CARD8 op,
+ PicturePtr src,
+ PicturePtr dst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ int screen = dst->pDrawable->pScreen->myNum;
+ pixman_image_t *image;
+ PixmapPtr scratch;
+ PicturePtr mask;
+ int width = 0, height = 0;
+ int x, y, n;
+ int xDst = list->xOff, yDst = list->yOff;
+ BoxRec extents = { 0, 0, 0, 0 };
+
+ if (maskFormat) {
+ pixman_format_code_t format;
+ CARD32 component_alpha;
+ int error;
+
+ 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;
+
+ format = maskFormat->format |
+ (BitsPerPixel(maskFormat->depth) << 24);
+ image =
+ pixman_image_create_bits(format, width, height, NULL, 0);
+ if (!image)
+ return;
+
+ scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ PIXMAN_FORMAT_BPP(format),
+ pixman_image_get_stride(image),
+ pixman_image_get_data(image));
+
+ if (!scratch) {
+ pixman_image_unref(image);
+ return;
+ }
+
+ component_alpha = NeedsComponent(maskFormat->format);
+ mask = CreatePicture(0, &scratch->drawable,
+ maskFormat, CPComponentAlpha,
+ &component_alpha, serverClient, &error);
+ if (!mask) {
+ FreeScratchPixmapHeader(scratch);
+ pixman_image_unref(image);
+ return;
+ }
+ ValidatePicture(mask);
+
+ x = -extents.x1;
+ y = -extents.y1;
+ } else {
+ mask = dst;
+ x = 0;
+ y = 0;
+ }
+
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+ PicturePtr g = GlyphPicture(glyph)[screen];
+ if (g) {
+ if (maskFormat) {
+ CompositePicture(PictOpAdd, g, NULL, mask,
+ 0, 0,
+ 0, 0,
+ x - glyph->info.x,
+ y - glyph->info.y,
+ glyph->info.width,
+ glyph->info.height);
+ } else {
+ CompositePicture(op, src, g, dst,
+ xSrc + (x - glyph->info.x) - xDst,
+ ySrc + (y - glyph->info.y) - yDst,
+ 0, 0,
+ x - glyph->info.x,
+ y - glyph->info.y,
+ glyph->info.width,
+ glyph->info.height);
+ }
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ if (maskFormat) {
+ x = extents.x1;
+ y = extents.y1;
+ CompositePicture(op, src, mask, dst,
+ xSrc + x - xDst,
+ ySrc + y - yDst,
+ 0, 0,
+ x, y,
+ width, height);
+ FreePicture(mask, 0);
+ FreeScratchPixmapHeader(scratch);
+ pixman_image_unref(image);
+ }
+}
+
+static inline unsigned int
+uxa_glyph_size_to_count(int size)
+{
+ size /= GLYPH_MIN_SIZE;
+ return size * size;
+}
+
+static inline unsigned int
+uxa_glyph_count_to_mask(int count)
+{
+ return ~(count - 1);
+}
+
+static inline unsigned int
+uxa_glyph_size_to_mask(int size)
+{
+ return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size));
+}
+
+static PicturePtr
+uxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PicturePtr glyph_picture = GlyphPicture(glyph)[screen->myNum];
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
+ struct uxa_glyph *priv = NULL;
+ int size, mask, pos, s;
+
+ if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE)
+ return NULL;
+
+ for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
+ if (glyph->info.width <= size && glyph->info.height <= size)
+ break;
+
+ s = uxa_glyph_size_to_count(size);
+ mask = uxa_glyph_count_to_mask(s);
+ pos = (cache->count + s - 1) & mask;
+ if (pos < GLYPH_CACHE_SIZE) {
+ cache->count = pos + s;
+ } else {
+ for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
+ int i = cache->evict & uxa_glyph_size_to_mask(s);
+ GlyphPtr evicted = cache->glyphs[i];
+ if (evicted == NULL)
+ continue;
+
+ priv = uxa_glyph_get_private(evicted);
+ if (priv->size >= s) {
+ cache->glyphs[i] = NULL;
+ uxa_glyph_set_private(evicted, NULL);
+ pos = cache->evict & uxa_glyph_size_to_mask(size);
+ } else
+ priv = NULL;
+ break;
+ }
+ if (priv == NULL) {
+ int count = uxa_glyph_size_to_count(size);
+ mask = uxa_glyph_count_to_mask(count);
+ pos = cache->evict & mask;
+ for (s = 0; s < count; s++) {
+ GlyphPtr evicted = cache->glyphs[pos + s];
+ if (evicted != NULL) {
+ if (priv != NULL)
+ xfree(priv);
+
+ priv = uxa_glyph_get_private(evicted);
+ uxa_glyph_set_private(evicted, NULL);
+ cache->glyphs[pos + s] = NULL;
+ }
+ }
+ }
+
+ /* And pick a new eviction position */
+ cache->evict = rand() % GLYPH_CACHE_SIZE;
+ }
+
+ if (priv == NULL) {
+ priv = xalloc(sizeof(struct uxa_glyph));
+ if (priv == NULL)
+ return NULL;
+ }
+
+ uxa_glyph_set_private(glyph, priv);
+ cache->glyphs[pos] = glyph;
+
+ priv->cache = cache;
+ priv->size = size;
+ priv->pos = pos;
+ s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
+ priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
+ priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
+ for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
+ if (pos & 1)
+ priv->x += s;
+ if (pos & 2)
+ priv->y += s;
+ pos >>= 2;
+ }
+
+ uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
+
+ *out_x = priv->x;
+ *out_y = priv->y;
+ return cache->picture;
+}
+
+static int
+uxa_glyphs_to_dst(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ INT16 src_x, INT16 src_y,
+ INT16 xDst, INT16 yDst,
+ int nlist, GlyphListPtr list, GlyphPtr * glyphs,
+ BoxPtr extents)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PixmapPtr src_pixmap, dst_pixmap;
+ PicturePtr localSrc, glyph_atlas;
+ int x, y, n, nrect;
+ BoxRec box;
+
+ if (uxa_screen->info->check_composite_texture &&
+ uxa_screen->info->check_composite_texture(screen, pSrc)) {
+ if (pSrc->pDrawable) {
+ int src_off_x, src_off_y;
+
+ src_pixmap = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (src_pixmap == NULL)
+ return -1;
+
+ src_x += pSrc->pDrawable->x + src_off_x;
+ src_y += pSrc->pDrawable->y + src_off_y;
+ } else {
+ src_pixmap = NULL;
+ }
+ localSrc = pSrc;
+ } else {
+ int width, height;
+
+ if (extents == NULL) {
+ uxa_glyph_extents(nlist, list, glyphs, &box);
+ extents = &box;
+ }
+
+ width = extents->x2 - extents->x1;
+ height = extents->y2 - extents->y1;
+ if (width == 0 || height == 0)
+ return 0;
+
+ if (pSrc->pDrawable) {
+ int src_off_x, src_off_y;
+
+ src_off_x = extents->x1 - xDst;
+ src_off_y = extents->y1 - yDst;
+ localSrc = uxa_acquire_drawable(screen, pSrc,
+ src_x + src_off_x, src_y + src_off_y,
+ width, height,
+ &src_x, &src_y);
+ if (uxa_screen->info->check_composite_texture &&
+ !uxa_screen->info->check_composite_texture(screen, localSrc)) {
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ return -1;
+ }
+
+ src_pixmap = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y);
+ if (src_pixmap == NULL) {
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ return -1;
+ }
+
+ src_x += localSrc->pDrawable->x + src_off_x;
+ src_y += localSrc->pDrawable->y + src_off_y;
+ } else {
+ localSrc = uxa_acquire_pattern(screen, pSrc,
+ PICT_a8r8g8b8, x, y, width, height);
+ if (!localSrc)
+ return 1;
+
+ src_pixmap = uxa_get_drawable_pixmap(localSrc->pDrawable);
+ if (src_pixmap == NULL) {
+ FreePicture(localSrc, 0);
+ return -1;
+ }
+
+ src_x = src_y = 0;
+ }
+ }
+
+ dst_pixmap = uxa_get_offscreen_pixmap(pDst->pDrawable, &x, &y);
+ x += xDst + pDst->pDrawable->x - list->xOff;
+ y += yDst + pDst->pDrawable->y - list->yOff;
+
+ glyph_atlas = NULL;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+ PicturePtr this_atlas;
+ int mask_x, mask_y;
+ struct uxa_glyph *priv;
+
+ if (glyph->info.width == 0 || glyph->info.height == 0)
+ goto next_glyph;
+
+ priv = uxa_glyph_get_private(glyph);
+ if (priv != NULL) {
+ mask_x = priv->x;
+ mask_y = priv->y;
+ this_atlas = priv->cache->picture;
+ } else {
+ if (glyph_atlas) {
+ uxa_screen->info->done_composite(dst_pixmap);
+ glyph_atlas = NULL;
+ }
+ this_atlas = uxa_glyph_cache(screen, glyph, &mask_x, &mask_y);
+ if (this_atlas == NULL) {
+ /* no cache for this glyph */
+ this_atlas = GlyphPicture(glyph)[screen->myNum];
+ mask_x = mask_y = 0;
+ }
+ }
+
+ if (this_atlas != glyph_atlas) {
+ PixmapPtr mask_pixmap;
+
+ if (glyph_atlas)
+ uxa_screen->info->done_composite(dst_pixmap);
+
+ mask_pixmap =
+ uxa_get_drawable_pixmap(this_atlas->pDrawable);
+ assert (uxa_pixmap_is_offscreen(mask_pixmap));
+
+ if (!uxa_screen->info->prepare_composite(op,
+ localSrc, this_atlas, pDst,
+ src_pixmap, mask_pixmap, dst_pixmap))
+ return -1;
+
+ glyph_atlas = this_atlas;
+ }
+
+ nrect = REGION_NUM_RECTS(pDst->pCompositeClip);
+ if (nrect == 1) {
+ uxa_screen->info->composite(dst_pixmap,
+ x + src_x, y + src_y,
+ mask_x, mask_y,
+ x - glyph->info.x,
+ y - glyph->info.y,
+ glyph->info.width,
+ glyph->info.height);
+ } else {
+ BoxPtr rects = REGION_RECTS(pDst->pCompositeClip);
+ do {
+ int x1 = x - glyph->info.x, dx = 0;
+ int y1 = y - glyph->info.y, dy = 0;
+ int x2 = x1 + glyph->info.width;
+ int y2 = y1 + glyph->info.height;
+
+ if (x1 < rects->x1)
+ dx = rects->x1 - x1, x1 = rects->x1;
+ if (x2 > rects->x2)
+ x2 = rects->x2;
+ if (y1 < rects->y1)
+ dy = rects->y1 - y1, y1 = rects->y1;
+ if (y2 > rects->y2)
+ y2 = rects->y2;
+
+ if (x1 < x2 && y1 < y2) {
+ uxa_screen->info->composite(dst_pixmap,
+ x1 + src_x, y1 + src_y,
+ dx + mask_x, dy + mask_y,
+ x1, y1,
+ x2 - x1, y2 - y1);
+ }
+ rects++;
+ } while (--nrect);
+ }
+
+next_glyph:
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+ if (glyph_atlas)
+ uxa_screen->info->done_composite(dst_pixmap);
+
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+
+ return 0;
+}
+
+static void
+uxa_clear_pixmap(ScreenPtr screen,
+ uxa_screen_t *uxa_screen,
+ PixmapPtr pixmap)
+{
+ if (uxa_screen->info->check_solid &&
+ !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES))
+ goto fallback;
+
+ if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0))
+ goto fallback;
+
+ uxa_screen->info->solid(pixmap,
+ 0, 0,
+ pixmap->drawable.width,
+ pixmap->drawable.height);
+
+ uxa_screen->info->done_solid(pixmap);
+ return;
+
+fallback:
+ {
+ GCPtr gc;
+
+ gc = GetScratchGC(pixmap->drawable.depth, screen);
+ if (gc) {
+ xRectangle rect;
+
+ ValidateGC(&pixmap->drawable, gc);
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = pixmap->drawable.width;
+ rect.height = pixmap->drawable.height;
+ gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect);
+
+ FreeScratchGC(gc);
+ }
+ }
+}
+
+static int
+uxa_glyphs_via_mask(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc,
+ INT16 xDst, INT16 yDst,
+ int nlist, GlyphListPtr list, GlyphPtr * glyphs,
+ BoxPtr extents)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ CARD32 component_alpha;
+ PixmapPtr pixmap;
+ PicturePtr glyph_atlas, mask;
+ int x, y, width, height;
+ int dst_off_x, dst_off_y;
+ int n, error;
+ BoxRec box;
+
+ if (!extents) {
+ uxa_glyph_extents(nlist, list, glyphs, &box);
+
+ if (box.x2 <= box.x1 || box.y2 <= box.y1)
+ return 0;
+
+ extents = &box;
+ dst_off_x = box.x1;
+ dst_off_y = box.y1;
+ } else {
+ dst_off_x = dst_off_y = 0;
+ }
+
+ width = extents->x2 - extents->x1;
+ height = extents->y2 - extents->y1;
+ x = -extents->x1;
+ y = -extents->y1;
+
+ if (maskFormat->depth == 1) {
+ PictFormatPtr a8Format =
+ PictureMatchFormat(screen, 8, PICT_a8);
+
+ if (!a8Format)
+ return -1;
+
+ maskFormat = a8Format;
+ }
+
+ pixmap = screen->CreatePixmap(screen, width, height,
+ maskFormat->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pixmap)
+ return 1;
+
+ uxa_clear_pixmap(screen, uxa_screen, pixmap);
+
+ component_alpha = NeedsComponent(maskFormat->format);
+ mask = CreatePicture(0, &pixmap->drawable,
+ maskFormat, CPComponentAlpha,
+ &component_alpha, serverClient, &error);
+ screen->DestroyPixmap(pixmap);
+
+ if (!mask)
+ return 1;
+
+ ValidatePicture(mask);
+
+ glyph_atlas = NULL;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--) {
+ GlyphPtr glyph = *glyphs++;
+ PicturePtr this_atlas;
+ int src_x, src_y;
+ struct uxa_glyph *priv;
+
+ if (glyph->info.width == 0 || glyph->info.height == 0)
+ goto next_glyph;
+
+ priv = uxa_glyph_get_private(glyph);
+ if (priv != NULL) {
+ src_x = priv->x;
+ src_y = priv->y;
+ this_atlas = priv->cache->picture;
+ } else {
+ if (glyph_atlas) {
+ uxa_screen->info->done_composite(pixmap);
+ glyph_atlas = NULL;
+ }
+ this_atlas = uxa_glyph_cache(screen, glyph, &src_x, &src_y);
+ if (this_atlas == NULL) {
+ /* no cache for this glyph */
+ this_atlas = GlyphPicture(glyph)[screen->myNum];
+ src_x = src_y = 0;
+ }
+ }
+
+ if (this_atlas != glyph_atlas) {
+ PixmapPtr src_pixmap;
+
+ if (glyph_atlas)
+ uxa_screen->info->done_composite(pixmap);
+
+ src_pixmap =
+ uxa_get_drawable_pixmap(this_atlas->pDrawable);
+ assert (uxa_pixmap_is_offscreen(src_pixmap));
+
+ if (!uxa_screen->info->prepare_composite(PictOpAdd,
+ this_atlas, NULL, mask,
+ src_pixmap, NULL, pixmap))
+ return -1;
+
+ glyph_atlas = this_atlas;
+ }
+
+ uxa_screen->info->composite(pixmap,
+ src_x, src_y,
+ 0, 0,
+ x - glyph->info.x,
+ y - glyph->info.y,
+ glyph->info.width,
+ glyph->info.height);
+
+next_glyph:
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+ if (glyph_atlas)
+ uxa_screen->info->done_composite(pixmap);
+
+ uxa_composite(op,
+ pSrc, mask, pDst,
+ dst_off_x + xSrc - xDst,
+ dst_off_y + ySrc - yDst,
+ 0, 0,
+ dst_off_x, dst_off_y,
+ width, height);
+
+ FreePicture(mask, 0);
+ return 0;
+}
+
+void
+uxa_glyphs(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc, INT16 ySrc,
+ int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ int xDst = list->xOff, yDst = list->yOff;
+ BoxRec extents = { 0, 0, 0, 0 };
+ Bool have_extents = FALSE;
+ int width, height, ret;
+ PicturePtr localDst = pDst;
+
+ if (!uxa_screen->info->prepare_composite ||
+ uxa_screen->swappedOut ||
+ uxa_screen->force_fallback ||
+ !uxa_drawable_is_offscreen(pDst->pDrawable) ||
+ pDst->alphaMap || pSrc->alphaMap) {
+fallback:
+ uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
+ return;
+ }
+
+ /* basic sanity check */
+ if (uxa_screen->info->check_composite &&
+ !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) {
+ goto fallback;
+ }
+
+ ValidatePicture(pSrc);
+ ValidatePicture(pDst);
+
+ if (!maskFormat) {
+ /* If we don't have a mask format but all the glyphs have the same format,
+ * require ComponentAlpha and don't intersect, use the glyph format as mask
+ * format for the full benefits of the glyph cache.
+ */
+ if (NeedsComponent(list[0].format->format)) {
+ 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 ||
+ uxa_glyphs_intersect(nlist, list, glyphs))
+ maskFormat = NULL;
+ }
+ }
+
+ if (!maskFormat &&
+ uxa_screen->info->check_composite_target &&
+ !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
+ int depth = pDst->pDrawable->depth;
+ PixmapPtr pixmap;
+ int x, y, error;
+ GCPtr gc;
+
+ pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
+ if (uxa_screen->info->check_copy &&
+ !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
+ goto fallback;
+
+ uxa_glyph_extents(nlist, list, glyphs, &extents);
+
+ /* clip against dst bounds */
+ if (extents.x1 < 0)
+ extents.x1 = 0;
+ if (extents.y1 < 0)
+ extents.y1 = 0;
+ if (extents.x2 > pDst->pDrawable->width)
+ extents.x2 = pDst->pDrawable->width;
+ if (extents.y2 > pDst->pDrawable->height)
+ extents.y2 = pDst->pDrawable->height;
+
+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ return;
+ width = extents.x2 - extents.x1;
+ height = extents.y2 - extents.y1;
+ x = -extents.x1;
+ y = -extents.y1;
+ have_extents = TRUE;
+
+ xDst += x;
+ yDst += y;
+
+ pixmap = screen->CreatePixmap(screen,
+ width, height, depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pixmap)
+ return;
+
+ gc = GetScratchGC(depth, screen);
+ if (!gc) {
+ screen->DestroyPixmap(pixmap);
+ return;
+ }
+
+ ValidateGC(&pixmap->drawable, gc);
+ gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
+ extents.x1, extents.y1,
+ width, height,
+ 0, 0);
+ FreeScratchGC(gc);
+
+ localDst = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen, depth, pDst->format),
+ 0, 0, serverClient, &error);
+ screen->DestroyPixmap(pixmap);
+
+ if (!localDst)
+ return;
+
+ ValidatePicture(localDst);
+ }
+
+ if (maskFormat) {
+ ret = uxa_glyphs_via_mask(op,
+ pSrc, localDst, maskFormat,
+ xSrc, ySrc,
+ xDst, yDst,
+ nlist, list, glyphs,
+ have_extents ? &extents : NULL);
+ } else {
+ ret = uxa_glyphs_to_dst(op,
+ pSrc, localDst,
+ xSrc, ySrc,
+ xDst, yDst,
+ nlist, list, glyphs,
+ have_extents ? &extents : NULL);
+ }
+ if (ret) {
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ goto fallback;
+ }
+
+ if (localDst != pDst) {
+ GCPtr gc;
+
+ gc = GetScratchGC(pDst->pDrawable->depth, screen);
+ if (gc) {
+ ValidateGC(pDst->pDrawable, gc);
+ gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
+ 0, 0,
+ width, height,
+ extents.x1, extents.y1);
+ FreeScratchGC(gc);
+ }
+
+ FreePicture(localDst, 0);
+ }
+}
diff --git a/src/uxa/uxa-priv.h b/src/uxa/uxa-priv.h
new file mode 100644
index 0000000..6492ca7
--- /dev/null
+++ b/src/uxa/uxa-priv.h
@@ -0,0 +1,426 @@
+/*
+ *
+ * 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_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+#include "xf86.h"
+
+#include "uxa.h"
+
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "dix.h"
+#include "fb.h"
+#include "fboverlay.h"
+#ifdef RENDER
+//#include "fbpict.h"
+#include "glyphstr.h"
+#endif
+#include "damage.h"
+
+/* Provide substitutes for gcc's __FUNCTION__ on other compilers */
+#if !defined(__GNUC__) && !defined(__FUNCTION__)
+# if defined(__STDC__) && (__STDC_VERSION__>=199901L) /* C99 */
+# define __FUNCTION__ __func__
+# else
+# define __FUNCTION__ ""
+# endif
+#endif
+
+/* 1.6 and earlier server compat */
+#ifndef miGetCompositeClip
+#define miCopyRegion fbCopyRegion
+#define miDoCopy fbDoCopy
+#endif
+
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#define DEBUG_OFFSCREEN 0
+#define DEBUG_GLYPH_CACHE 0
+
+#define UXA_FALLBACK(x) \
+if (uxa_get_screen(screen)->fallback_debug) { \
+ ErrorF("UXA fallback at %s: ", __FUNCTION__); \
+ ErrorF x; \
+}
+
+char uxa_drawable_location(DrawablePtr pDrawable);
+
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+
+typedef struct {
+ PicturePtr picture; /* Where the glyphs of the cache are stored */
+ GlyphPtr *glyphs;
+ uint16_t count;
+ uint16_t evict;
+} uxa_glyph_cache_t;
+
+#define UXA_NUM_GLYPH_CACHE_FORMATS 2
+
+typedef struct {
+ uint32_t color;
+ PicturePtr picture;
+} uxa_solid_cache_t;
+
+#define UXA_NUM_SOLID_CACHE 16
+
+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;
+ CompositeRectsProcPtr SavedCompositeRects;
+ TrianglesProcPtr SavedTriangles;
+ GlyphsProcPtr SavedGlyphs;
+ TrapezoidsProcPtr SavedTrapezoids;
+ AddTrapsProcPtr SavedAddTraps;
+ UnrealizeGlyphProcPtr SavedUnrealizeGlyph;
+#endif
+ EnableDisableFBAccessProcPtr SavedEnableDisableFBAccess;
+
+ Bool force_fallback;
+ Bool fallback_debug;
+ Bool swappedOut;
+ unsigned disableFbCount;
+ unsigned offScreenCounter;
+
+ uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHE_FORMATS];
+
+ PicturePtr solid_clear, solid_black, solid_white;
+ uxa_solid_cache_t solid_cache[UXA_NUM_SOLID_CACHE];
+ int solid_cache_size;
+} 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 int uxa_screen_index;
+static inline uxa_screen_t *uxa_get_screen(ScreenPtr screen)
+{
+ return (uxa_screen_t *) dixLookupPrivate(&screen->devPrivates,
+ &uxa_screen_index);
+}
+
+/** 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);
+
+Bool uxa_prepare_access_window(WindowPtr pWin);
+
+void uxa_finish_access_window(WindowPtr pWin);
+
+/* uxa-unaccel.c */
+Bool 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_paint_window(WindowPtr pWin, RegionPtr pRegion, int what);
+
+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_paint_window(WindowPtr pWin, RegionPtr pRegion, int what);
+
+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 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 */
+Bool uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access);
+
+void uxa_finish_access(DrawablePtr pDrawable);
+
+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_solid_rects (CARD8 op,
+ PicturePtr dst,
+ xRenderColor *color,
+ int num_rects,
+ xRectangle *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);
+
+PicturePtr
+uxa_acquire_solid(ScreenPtr screen, SourcePict *source);
+
+PicturePtr
+uxa_acquire_drawable(ScreenPtr pScreen,
+ PicturePtr pSrc,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y);
+
+PicturePtr
+uxa_acquire_pattern(ScreenPtr pScreen,
+ PicturePtr pSrc,
+ pixman_format_code_t format,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height);
+
+Bool
+uxa_get_rgba_from_pixel(CARD32 pixel,
+ CARD16 * red,
+ CARD16 * green,
+ CARD16 * blue,
+ CARD16 * alpha,
+ CARD32 format);
+
+/* uxa_glyph.c */
+Bool 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);
+
+void
+uxa_glyph_unrealize(ScreenPtr pScreen,
+ GlyphPtr pGlyph);
+
+#endif /* UXAPRIV_H */
diff --git a/src/uxa/uxa-render.c b/src/uxa/uxa-render.c
new file mode 100644
index 0000000..0e4fa91
--- /dev/null
+++ b/src/uxa/uxa-render.c
@@ -0,0 +1,1957 @@
+/*
+ * 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"
+#include <xorgVersion.h>
+
+#ifdef RENDER
+#include "mipict.h"
+
+static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
+ int n)
+{
+ char format[20];
+ char size[20];
+ char loc;
+
+ if (!pict) {
+ snprintf(string, n, "None");
+ return;
+ }
+
+ if (pict->pDrawable == NULL) {
+ snprintf(string, n, "source-only");
+ 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_drawable_is_offscreen(pict->pDrawable) ? '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)%s",
+ pict->pDrawable, loc, format, size,
+ pict->alphaMap ? " with alpha map" :"");
+}
+
+static const char *
+op_to_string(CARD8 op)
+{
+ switch (op) {
+#define C(x) case PictOp##x: return #x
+ C(Clear);
+ C(Src);
+ C(Dst);
+ C(Over);
+ C(OverReverse);
+ C(In);
+ C(InReverse);
+ C(Out);
+ C(OutReverse);
+ C(Atop);
+ C(AtopReverse);
+ C(Xor);
+ C(Add);
+ C(Saturate);
+
+ /*
+ * Operators only available in version 0.2
+ */
+ C(DisjointClear);
+ C(DisjointSrc);
+ C(DisjointDst);
+ C(DisjointOver);
+ C(DisjointOverReverse);
+ C(DisjointIn);
+ C(DisjointInReverse);
+ C(DisjointOut);
+ C(DisjointOutReverse);
+ C(DisjointAtop);
+ C(DisjointAtopReverse);
+ C(DisjointXor);
+
+ C(ConjointClear);
+ C(ConjointSrc);
+ C(ConjointDst);
+ C(ConjointOver);
+ C(ConjointOverReverse);
+ C(ConjointIn);
+ C(ConjointInReverse);
+ C(ConjointOut);
+ C(ConjointOutReverse);
+ C(ConjointAtop);
+ C(ConjointAtopReverse);
+ C(ConjointXor);
+
+ /*
+ * Operators only available in version 0.11
+ */
+ C(Multiply);
+ C(Screen);
+ C(Overlay);
+ C(Darken);
+ C(Lighten);
+ C(ColorDodge);
+ C(ColorBurn);
+ C(HardLight);
+ C(SoftLight);
+ C(Difference);
+ C(Exclusion);
+ C(HSLHue);
+ C(HSLSaturation);
+ C(HSLColor);
+ C(HSLLuminosity);
+ default: return "garbage";
+#undef C
+ }
+}
+
+static void
+uxa_print_composite_fallback(const char *func, CARD8 op,
+ PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ char srcdesc[40], maskdesc[40], dstdesc[40];
+
+ if (! uxa_screen->fallback_debug)
+ return;
+
+ /* Limit the noise if fallbacks are expected. */
+ if (uxa_screen->force_fallback)
+ return;
+
+ 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 at %s:\n"
+ " op %s, \n"
+ " src %s, \n"
+ " mask %s, \n"
+ " dst %s, \n"
+ " screen %s\n",
+ func, op_to_string (op), srcdesc, maskdesc, dstdesc,
+ uxa_screen->swappedOut ? "swapped out" : "normal");
+}
+
+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;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+ if (abits == 0)
+ abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
+ *pixel = alpha >> (16 - abits);
+ return TRUE;
+ }
+
+ if (!PICT_FORMAT_COLOR(format))
+ return FALSE;
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
+ ashift = 0;
+ rshift = abits;
+ gshift = rshift + rbits;
+ bshift = gshift + gbits;
+ } else {
+ return FALSE;
+ }
+
+ *pixel = 0;
+ *pixel |= (blue >> (16 - bbits)) << bshift;
+ *pixel |= (green >> (16 - gbits)) << gshift;
+ *pixel |= (red >> (16 - rbits)) << rshift;
+ *pixel |= (alpha >> (16 - abits)) << ashift;
+
+ return TRUE;
+}
+
+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;
+
+ 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_A) {
+ rshift = gshift = bshift = ashift = 0;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
+ ashift = 0;
+ rshift = abits;
+ if (abits == 0)
+ rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
+ gshift = rshift + rbits;
+ bshift = gshift + gbits;
+ } else {
+ return FALSE;
+ }
+
+ if (rbits) {
+ *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
+ while (rbits < 16) {
+ *red |= *red >> rbits;
+ rbits <<= 1;
+ }
+ } else
+ *red = 0;
+
+ if (gbits) {
+ *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
+ while (gbits < 16) {
+ *green |= *green >> gbits;
+ gbits <<= 1;
+ }
+ } else
+ *green = 0;
+
+ if (bbits) {
+ *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
+ while (bbits < 16) {
+ *blue |= *blue >> bbits;
+ bbits <<= 1;
+ }
+ } else
+ *blue = 0;
+
+ if (abits) {
+ *alpha =
+ ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
+ while (abits < 16) {
+ *alpha |= *alpha >> abits;
+ abits <<= 1;
+ }
+ } else
+ *alpha = 0xffff;
+
+ return TRUE;
+}
+
+Bool
+uxa_get_color_for_pixmap (PixmapPtr pixmap,
+ CARD32 src_format,
+ CARD32 dst_format,
+ CARD32 *pixel)
+{
+ CARD16 red, green, blue, alpha;
+
+ *pixel = uxa_get_pixmap_first_pixel(pixmap);
+
+ if (src_format != dst_format) {
+ if (!uxa_get_rgba_from_pixel(*pixel,
+ &red, &green, &blue, &alpha,
+ src_format))
+ return FALSE;
+
+ if (!uxa_get_pixel_from_rgba(pixel,
+ red, green, blue, alpha,
+ dst_format))
+ return FALSE;
+ }
+
+ 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 = NULL, pDstPix;
+ CARD32 pixel;
+
+ if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
+ return -1;
+
+ pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
+ if (!pDstPix)
+ return -1;
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+
+ if (pSrc->pDrawable) {
+ pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+ }
+
+ if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ width, height))
+ return 1;
+
+ if (pSrcPix) {
+ if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+ } else {
+ SourcePict *source = pSrc->pSourcePict;
+ PictSolidFill *solid = &source->solidFill;
+
+ if (source == NULL || source->type != SourcePictTypeSolidFill) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (pDst->format == PICT_a8r8g8b8) {
+ pixel = solid->color;
+ } else if (pDst->format == PICT_x8r8g8b8) {
+ pixel = solid->color | 0xff000000;
+ } else {
+ CARD16 red, green, blue, alpha;
+
+ if (!uxa_get_rgba_from_pixel(solid->color,
+ &red, &green, &blue, &alpha,
+ PICT_a8r8g8b8) ||
+ !uxa_get_pixel_from_rgba(&pixel,
+ red, green, blue, alpha,
+ pDst->format)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+ }
+ }
+
+ if (!(*uxa_screen->info->prepare_solid)
+ (pDstPix, GXcopy, FB_ALLONES, pixel)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ 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->done_solid) (pDstPix);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+static PicturePtr
+uxa_picture_for_pixman_format(ScreenPtr pScreen,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ PicturePtr pPicture;
+ PixmapPtr pPixmap;
+ int error;
+
+ if (format == PIXMAN_a1)
+ format = PIXMAN_a8;
+
+ /* fill alpha if unset */
+ if (PIXMAN_FORMAT_A(format) == 0)
+ format = PIXMAN_a8r8g8b8;
+
+ pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ UXA_CREATE_PIXMAP_FOR_MAP);
+ if (!pPixmap)
+ return 0;
+
+ pPicture = CreatePicture(0, &pPixmap->drawable,
+ PictureMatchFormat(pScreen,
+ PIXMAN_FORMAT_DEPTH(format),
+ format),
+ 0, 0, serverClient, &error);
+ (*pScreen->DestroyPixmap) (pPixmap);
+ if (!pPicture)
+ return 0;
+
+ ValidatePicture(pPicture);
+
+ return pPicture;
+}
+
+static PicturePtr
+uxa_picture_from_pixman_image(ScreenPtr screen,
+ pixman_image_t * image,
+ pixman_format_code_t format)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PicturePtr picture;
+ PixmapPtr pixmap;
+ int width, height;
+
+ width = pixman_image_get_width(image);
+ height = pixman_image_get_height(image);
+
+ picture = uxa_picture_for_pixman_format(screen, format,
+ width, height);
+ if (!picture)
+ return 0;
+
+ if (uxa_screen->info->put_image &&
+ ((picture->pDrawable->depth << 24) | picture->format) == format &&
+ uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
+ 0, 0,
+ width, height,
+ (char *)pixman_image_get_data(image),
+ pixman_image_get_stride(image)))
+ return picture;
+
+ pixmap = GetScratchPixmapHeader(screen, width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ PIXMAN_FORMAT_BPP(format),
+ pixman_image_get_stride(image),
+ pixman_image_get_data(image));
+ if (!pixmap) {
+ FreePicture(picture, 0);
+ return 0;
+ }
+
+ if (((picture->pDrawable->depth << 24) | picture->format) == format) {
+ GCPtr gc;
+
+ gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
+ if (!gc) {
+ FreeScratchPixmapHeader(pixmap);
+ FreePicture(picture, 0);
+ return 0;
+ }
+ ValidateGC(picture->pDrawable, gc);
+
+ (*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
+ gc, 0, 0, width, height, 0, 0);
+
+ FreeScratchGC(gc);
+ } else {
+ PicturePtr src;
+ int error;
+
+ src = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format),
+ format),
+ 0, 0, serverClient, &error);
+ if (!src) {
+ FreeScratchPixmapHeader(pixmap);
+ FreePicture(picture, 0);
+ return 0;
+ }
+ ValidatePicture(src);
+
+ if (uxa_prepare_access(picture->pDrawable, UXA_ACCESS_RW)) {
+ fbComposite(PictOpSrc, src, NULL, picture,
+ 0, 0, 0, 0, 0, 0, width, height);
+ uxa_finish_access(picture->pDrawable);
+ }
+
+ FreePicture(src, 0);
+ }
+ FreeScratchPixmapHeader(pixmap);
+
+ return picture;
+}
+
+static PicturePtr
+uxa_create_solid(ScreenPtr screen, uint32_t color)
+{
+ PixmapPtr pixmap;
+ PicturePtr picture;
+ XID repeat = RepeatNormal;
+ int error = 0;
+
+ pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
+ UXA_CREATE_PIXMAP_FOR_MAP);
+ if (!pixmap)
+ return 0;
+
+ if (!uxa_prepare_access((DrawablePtr)pixmap, UXA_ACCESS_RW)) {
+ (*screen->DestroyPixmap)(pixmap);
+ return 0;
+ }
+ *((uint32_t *)pixmap->devPrivate.ptr) = color;
+ uxa_finish_access((DrawablePtr)pixmap);
+
+ picture = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
+ CPRepeat, &repeat, serverClient, &error);
+ (*screen->DestroyPixmap)(pixmap);
+
+ return picture;
+}
+
+static PicturePtr
+uxa_solid_clear(ScreenPtr screen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PicturePtr picture;
+
+ if (!uxa_screen->solid_clear) {
+ uxa_screen->solid_clear = uxa_create_solid(screen, 0);
+ if (!uxa_screen->solid_clear)
+ return 0;
+ }
+ picture = uxa_screen->solid_clear;
+ return picture;
+}
+
+PicturePtr
+uxa_acquire_solid(ScreenPtr screen, SourcePict *source)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PictSolidFill *solid = &source->solidFill;
+ PicturePtr picture;
+ int i;
+
+ if ((solid->color >> 24) == 0) {
+ picture = uxa_solid_clear(screen);
+ if (!picture)
+ return 0;
+
+ goto DONE;
+ } else if (solid->color == 0xff000000) {
+ if (!uxa_screen->solid_black) {
+ uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
+ if (!uxa_screen->solid_black)
+ return 0;
+ }
+ picture = uxa_screen->solid_black;
+ goto DONE;
+ } else if (solid->color == 0xffffffff) {
+ if (!uxa_screen->solid_white) {
+ uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
+ if (!uxa_screen->solid_white)
+ return 0;
+ }
+ picture = uxa_screen->solid_white;
+ goto DONE;
+ }
+
+ for (i = 0; i < uxa_screen->solid_cache_size; i++) {
+ if (uxa_screen->solid_cache[i].color == solid->color) {
+ picture = uxa_screen->solid_cache[i].picture;
+ goto DONE;
+ }
+ }
+
+ picture = uxa_create_solid(screen, solid->color);
+ if (!picture)
+ return 0;
+
+ if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
+ i = rand() % UXA_NUM_SOLID_CACHE;
+ FreePicture(uxa_screen->solid_cache[i].picture, 0);
+ } else
+ uxa_screen->solid_cache_size++;
+
+ uxa_screen->solid_cache[i].picture = picture;
+ uxa_screen->solid_cache[i].color = solid->color;
+
+DONE:
+ picture->refcnt++;
+ return picture;
+}
+
+PicturePtr
+uxa_acquire_pattern(ScreenPtr pScreen,
+ PicturePtr pSrc,
+ pixman_format_code_t format,
+ INT16 x, INT16 y, CARD16 width, CARD16 height)
+{
+ PicturePtr pDst;
+
+ if (pSrc->pSourcePict) {
+ SourcePict *source = pSrc->pSourcePict;
+ if (source->type == SourcePictTypeSolidFill)
+ return uxa_acquire_solid (pScreen, source);
+ }
+
+ pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
+ if (!pDst)
+ return 0;
+
+ if (uxa_prepare_access(pDst->pDrawable, UXA_ACCESS_RW)) {
+ fbComposite(PictOpSrc, pSrc, NULL, pDst,
+ x, y, 0, 0, 0, 0, width, height);
+ uxa_finish_access(pDst->pDrawable);
+ return pDst;
+ } else {
+ FreePicture(pDst, 0);
+ return 0;
+ }
+}
+
+static Bool
+transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
+{
+ if (t == NULL) {
+ *tx = *ty = 0;
+ return TRUE;
+ }
+
+ if (t->matrix[0][0] != IntToxFixed(1) ||
+ t->matrix[0][1] != 0 ||
+ t->matrix[1][0] != 0 ||
+ t->matrix[1][1] != IntToxFixed(1) ||
+ t->matrix[2][0] != 0 ||
+ t->matrix[2][1] != 0 ||
+ t->matrix[2][2] != IntToxFixed(1))
+ return FALSE;
+
+ if (xFixedFrac(t->matrix[0][2]) != 0 ||
+ xFixedFrac(t->matrix[1][2]) != 0)
+ return FALSE;
+
+ *tx = xFixedToInt(t->matrix[0][2]);
+ *ty = xFixedToInt(t->matrix[1][2]);
+ return TRUE;
+}
+
+static PicturePtr
+uxa_render_picture(ScreenPtr screen,
+ PicturePtr src,
+ pixman_format_code_t format,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height)
+{
+ PicturePtr picture;
+ int ret = 0;
+
+ /* XXX we need a mechanism for the card to choose the fallback format */
+
+ /* force alpha channel in case source does not entirely cover the extents */
+ if (PIXMAN_FORMAT_A(format) == 0)
+ format = PIXMAN_a8r8g8b8; /* available on all hardware */
+
+ picture = uxa_picture_for_pixman_format(screen, format, width, height);
+ if (!picture)
+ return 0;
+
+ if (uxa_prepare_access(picture->pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(src->pDrawable, UXA_ACCESS_RO)) {
+ ret = 1;
+ fbComposite(PictOpSrc, src, NULL, picture,
+ x, y, 0, 0, 0, 0, width, height);
+ uxa_finish_access(src->pDrawable);
+ }
+ uxa_finish_access(picture->pDrawable);
+ }
+
+ if (!ret) {
+ FreePicture(picture, 0);
+ return 0;
+ }
+
+ return picture;
+}
+
+PicturePtr
+uxa_acquire_drawable(ScreenPtr pScreen,
+ PicturePtr pSrc,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y)
+{
+ PixmapPtr pPixmap;
+ PicturePtr pDst;
+ GCPtr pGC;
+ int depth, error;
+ int tx, ty;
+
+ depth = pSrc->pDrawable->depth;
+ if (depth == 1 ||
+ pSrc->filter == PictFilterConvolution || /* XXX */
+ !transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
+ /* XXX extract the sample extents and do the transformation on the GPU */
+ pDst = uxa_render_picture(pScreen, pSrc,
+ pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
+ x, y, width, height);
+
+ goto done;
+ } else {
+ if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->depth) {
+ *out_x = x + pSrc->pDrawable->x;
+ *out_y = y + pSrc->pDrawable->y;
+ return pSrc;
+ }
+ }
+
+ pPixmap = pScreen->CreatePixmap(pScreen,
+ width, height, depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pPixmap)
+ return 0;
+
+ /* Skip the copy if the result remains in memory and not a bo */
+ if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) {
+ pScreen->DestroyPixmap(pPixmap);
+ return 0;
+ }
+
+ pGC = GetScratchGC(depth, pScreen);
+ if (!pGC) {
+ pScreen->DestroyPixmap(pPixmap);
+ return 0;
+ }
+
+ ValidateGC(&pPixmap->drawable, pGC);
+ pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
+ x + tx, y + ty, width, height, 0, 0);
+ FreeScratchGC(pGC);
+
+ pDst = CreatePicture(0, &pPixmap->drawable,
+ PictureMatchFormat(pScreen, depth, pSrc->format),
+ 0, 0, serverClient, &error);
+ pScreen->DestroyPixmap(pPixmap);
+ ValidatePicture(pDst);
+
+done:
+ pDst->componentAlpha = pSrc->componentAlpha;
+ *out_x = x;
+ *out_y = y;
+ return pDst;
+}
+
+static PicturePtr
+uxa_acquire_picture(ScreenPtr screen,
+ PicturePtr src,
+ pixman_format_code_t format,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+
+ if (uxa_screen->info->check_composite_texture &&
+ uxa_screen->info->check_composite_texture(screen, src)) {
+ if (src->pDrawable) {
+ *out_x = x + src->pDrawable->x;
+ *out_y = y + src->pDrawable->y;
+ } else {
+ *out_x = 0;
+ *out_y = 0;
+ }
+ return src;
+ }
+
+ if (src->pDrawable) {
+ PicturePtr dst;
+
+ dst = uxa_acquire_drawable(screen, src,
+ x, y, width, height,
+ out_x, out_y);
+ if (uxa_screen->info->check_composite_texture &&
+ !uxa_screen->info->check_composite_texture(screen, dst)) {
+ if (dst != src)
+ FreePicture(dst, 0);
+ return 0;
+ }
+
+ return dst;
+ }
+
+ *out_x = 0;
+ *out_y = 0;
+ return uxa_acquire_pattern(screen, src,
+ format, x, y, width, height);
+}
+
+static PicturePtr
+uxa_acquire_source(ScreenPtr screen,
+ PicturePtr pict,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y)
+{
+ return uxa_acquire_picture (screen, pict,
+ PICT_a8r8g8b8,
+ x, y,
+ width, height,
+ out_x, out_y);
+}
+
+static PicturePtr
+uxa_acquire_mask(ScreenPtr screen,
+ PicturePtr pict,
+ INT16 x, INT16 y,
+ INT16 width, INT16 height,
+ INT16 * out_x, INT16 * out_y)
+{
+ return uxa_acquire_picture (screen, pict,
+ PICT_a8,
+ x, y,
+ width, height,
+ out_x, out_y);
+}
+
+static Bool
+_pixman_region_init_rectangles(pixman_region16_t *region,
+ int num_rects,
+ xRectangle *rects,
+ int tx, int ty)
+{
+ pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
+ pixman_bool_t ret;
+ int i;
+
+ if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) {
+ boxes = xalloc(sizeof(pixman_box16_t) * num_rects);
+ if (boxes == NULL)
+ return FALSE;
+ }
+
+ for (i = 0; i < num_rects; i++) {
+ boxes[i].x1 = rects[i].x + tx;
+ boxes[i].y1 = rects[i].y + ty;
+ boxes[i].x2 = rects[i].x + tx + rects[i].width;
+ boxes[i].y2 = rects[i].y + ty + rects[i].height;
+ }
+
+ ret = pixman_region_init_rects(region, boxes, num_rects);
+
+ if (boxes != stack_boxes)
+ xfree(boxes);
+
+ return ret;
+}
+
+void
+uxa_solid_rects (CARD8 op,
+ PicturePtr dst,
+ xRenderColor *color,
+ int num_rects,
+ xRectangle *rects)
+{
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PixmapPtr dst_pixmap, src_pixmap = NULL;
+ pixman_region16_t region;
+ pixman_box16_t *boxes, *extents;
+ PicturePtr src;
+ int dst_x, dst_y;
+ int num_boxes;
+
+ if (!pixman_region_not_empty(dst->pCompositeClip))
+ return;
+
+ if (dst->alphaMap)
+ goto fallback;
+
+ dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y);
+ if (!dst_pixmap)
+ goto fallback;
+
+ if (!_pixman_region_init_rectangles(&region,
+ num_rects, rects,
+ dst->pDrawable->x, dst->pDrawable->y))
+ goto fallback;
+
+ if (!pixman_region_intersect(&region, &region, dst->pCompositeClip)) {
+ pixman_region_fini(&region);
+ return;
+ }
+
+ /* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
+ * manually append the damaged regions ourselves.
+ */
+ DamageRegionAppend(dst->pDrawable, &region);
+
+ pixman_region_translate(&region, dst_x, dst_y);
+ boxes = pixman_region_rectangles(&region, &num_boxes);
+ extents = pixman_region_extents (&region);
+
+ if (op == PictOpClear)
+ color->red = color->green = color->blue = color->alpha = 0;
+ if (color->alpha >= 0xff00 && op == PictOpOver) {
+ color->alpha = 0xffff;
+ op = PictOpSrc;
+ }
+
+ /* Using GEM, the relocation costs outweigh the advantages of the blitter */
+ if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) {
+ CARD32 pixel;
+
+try_solid:
+ if (uxa_screen->info->check_solid &&
+ !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES))
+ goto err_region;
+
+ if (!uxa_get_pixel_from_rgba(&pixel,
+ color->red,
+ color->green,
+ color->blue,
+ color->alpha,
+ dst->format))
+ goto err_region;
+
+ if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel))
+ goto err_region;
+
+ while (num_boxes--) {
+ uxa_screen->info->solid(dst_pixmap,
+ boxes->x1, boxes->y1,
+ boxes->x2, boxes->y2);
+ boxes++;
+ }
+
+ uxa_screen->info->done_solid(dst_pixmap);
+ } else {
+ int error;
+
+ src = CreateSolidPicture(0, color, &error);
+ if (!src)
+ goto err_region;
+
+ if (!uxa_screen->info->check_composite(op, src, NULL, dst,
+ extents->x2 - extents->x1,
+ extents->y2 - extents->y1)) {
+ if (op == PictOpSrc || op == PictOpClear) {
+ FreePicture(src, 0);
+ goto try_solid;
+ }
+
+ goto err_src;
+ }
+
+ if (!uxa_screen->info->check_composite_texture ||
+ !uxa_screen->info->check_composite_texture(screen, src)) {
+ PicturePtr solid;
+ int src_off_x, src_off_y;
+
+ solid = uxa_acquire_solid(screen, src->pSourcePict);
+ FreePicture(src, 0);
+
+ src = solid;
+ src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
+ &src_off_x, &src_off_y);
+ if (!src_pixmap)
+ goto err_src;
+ }
+
+ if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap))
+ goto err_src;
+
+ while (num_boxes--) {
+ uxa_screen->info->composite(dst_pixmap,
+ 0, 0, 0, 0,
+ boxes->x1,
+ boxes->y1,
+ boxes->x2 - boxes->x1,
+ boxes->y2 - boxes->y1);
+ boxes++;
+ }
+
+ uxa_screen->info->done_composite(dst_pixmap);
+ FreePicture(src, 0);
+ }
+
+ pixman_region_fini(&region);
+ return;
+
+err_src:
+ FreePicture(src, 0);
+err_region:
+ pixman_region_fini(&region);
+fallback:
+ uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects);
+}
+
+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)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+ int xDst_copy, yDst_copy;
+ int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
+ PicturePtr localSrc, localMask = NULL;
+ PicturePtr localDst = pDst;
+
+ if (uxa_screen->info->check_composite &&
+ !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
+ return -1;
+
+ if (uxa_screen->info->check_composite_target &&
+ !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
+ int depth = pDst->pDrawable->depth;
+ PixmapPtr pixmap;
+ int error;
+ GCPtr gc;
+
+ pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
+ if (uxa_screen->info->check_copy &&
+ !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
+ return -1;
+
+ pixmap = screen->CreatePixmap(screen,
+ width, height, depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pixmap)
+ return 0;
+
+ gc = GetScratchGC(depth, screen);
+ if (!gc) {
+ screen->DestroyPixmap(pixmap);
+ return 0;
+ }
+
+ ValidateGC(&pixmap->drawable, gc);
+ gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
+ xDst, yDst, width, height, 0, 0);
+ FreeScratchGC(gc);
+
+ xDst_copy = xDst; xDst = 0;
+ yDst_copy = yDst; yDst = 0;
+
+ localDst = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen, depth, pDst->format),
+ 0, 0, serverClient, &error);
+ screen->DestroyPixmap(pixmap);
+
+ if (!localDst)
+ return 0;
+
+ ValidatePicture(localDst);
+ }
+
+ pDstPix =
+ uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
+ if (!pDstPix) {
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+ return -1;
+ }
+
+ xDst += localDst->pDrawable->x;
+ yDst += localDst->pDrawable->y;
+
+ localSrc = uxa_acquire_source(screen, pSrc,
+ xSrc, ySrc,
+ width, height,
+ &xSrc, &ySrc);
+ if (!localSrc) {
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+ return 0;
+ }
+
+ if (pMask) {
+ localMask = uxa_acquire_mask(screen, pMask,
+ xMask, yMask,
+ width, height,
+ &xMask, &yMask);
+ if (!localMask) {
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ return 0;
+ }
+ }
+
+ if (!miComputeCompositeRegion(&region, localSrc, localMask, localDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height)) {
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ return 1;
+ }
+
+ if (localSrc->pDrawable) {
+ pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
+ &src_off_x, &src_off_y);
+ if (!pSrcPix) {
+ REGION_UNINIT(screen, &region);
+
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ return 0;
+ }
+ } else {
+ pSrcPix = NULL;
+ }
+
+ if (localMask) {
+ if (localMask->pDrawable) {
+ pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
+ &mask_off_x, &mask_off_y);
+ if (!pMaskPix) {
+ REGION_UNINIT(screen, &region);
+
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ return 0;
+ }
+ } else {
+ pMaskPix = NULL;
+ }
+ }
+
+ if (!(*uxa_screen->info->prepare_composite)
+ (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
+ REGION_UNINIT(screen, &region);
+
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+ if (localDst != pDst)
+ FreePicture(localDst, 0);
+
+ return -1;
+ }
+
+ if (pMask) {
+ xMask = xMask + mask_off_x - xDst;
+ yMask = yMask + mask_off_y - yDst;
+ }
+
+ xSrc = xSrc + src_off_x - xDst;
+ ySrc = ySrc + src_off_y - yDst;
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+ while (nbox--) {
+ (*uxa_screen->info->composite) (pDstPix,
+ pbox->x1 + xSrc,
+ pbox->y1 + ySrc,
+ pbox->x1 + xMask,
+ pbox->y1 + yMask,
+ pbox->x1 + dst_off_x,
+ pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+ (*uxa_screen->info->done_composite) (pDstPix);
+
+ REGION_UNINIT(screen, &region);
+
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+
+ if (localDst != pDst) {
+ GCPtr gc;
+
+ gc = GetScratchGC(pDst->pDrawable->depth, screen);
+ if (gc) {
+ ValidateGC(pDst->pDrawable, gc);
+ gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
+ 0, 0, width, height, xDst_copy, yDst_copy);
+ FreeScratchGC(gc);
+ }
+
+ FreePicture(localDst, 0);
+ }
+
+ 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)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+ PicturePtr localDst = pDst;
+ int xDst_copy, yDst_copy;
+
+ assert(op == PictOpOver);
+
+ if (uxa_screen->info->check_composite &&
+ (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
+ pMask, pDst, width, height)
+ || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
+ pDst, width, height))) {
+ return -1;
+ }
+
+ if (uxa_screen->info->check_composite_target &&
+ !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
+ int depth = pDst->pDrawable->depth;
+ PixmapPtr pixmap;
+ int error;
+ GCPtr gc;
+
+ pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
+ if (uxa_screen->info->check_copy &&
+ !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
+ return -1;
+
+ pixmap = screen->CreatePixmap(screen,
+ width, height, depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pixmap)
+ return 0;
+
+ gc = GetScratchGC(depth, screen);
+ if (!gc) {
+ screen->DestroyPixmap(pixmap);
+ return 0;
+ }
+
+ ValidateGC(&pixmap->drawable, gc);
+ gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
+ xDst, yDst, width, height, 0, 0);
+ FreeScratchGC(gc);
+
+ xDst_copy = xDst; xDst = 0;
+ yDst_copy = yDst; yDst = 0;
+
+ localDst = CreatePicture(0, &pixmap->drawable,
+ PictureMatchFormat(screen, depth, pDst->format),
+ 0, 0, serverClient, &error);
+ screen->DestroyPixmap(pixmap);
+
+ if (!localDst)
+ return 0;
+
+ ValidatePicture(localDst);
+ }
+
+ /* 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, localDst,
+ 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, localDst,
+ xSrc, ySrc,
+ xMask, yMask,
+ xDst, yDst,
+ width, height);
+
+ if (localDst != pDst) {
+ GCPtr gc;
+
+ gc = GetScratchGC(pDst->pDrawable->depth, screen);
+ if (gc) {
+ ValidateGC(pDst->pDrawable, gc);
+ gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
+ 0, 0, width, height, xDst_copy, yDst_copy);
+ FreeScratchGC(gc);
+ }
+
+ FreePicture(localDst, 0);
+ }
+
+ return 1;
+}
+
+static int
+compatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
+{
+ if (op == PictOpSrc) {
+ if (src->format == dst->format)
+ return 1;
+
+ /* Is the destination an alpha-less version of source? */
+ if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
+ PICT_FORMAT_TYPE(src->format),
+ 0,
+ PICT_FORMAT_R(src->format),
+ PICT_FORMAT_G(src->format),
+ PICT_FORMAT_B(src->format)))
+ return 1;
+
+ /* XXX xrgb is promoted to argb during image upload... */
+#if 0
+ if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
+ return 1;
+#endif
+ } else if (op == PictOpOver) {
+ if (PICT_FORMAT_A(src->format))
+ return 0;
+
+ return src->format == dst->format;
+ }
+
+ return 0;
+}
+
+static int
+drawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
+{
+ if (x < 0 || y < 0)
+ return FALSE;
+
+ if (x + w > drawable->width)
+ return FALSE;
+
+ if (y + h > drawable->height)
+ return FALSE;
+
+ return TRUE;
+}
+
+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;
+ int tx, ty;
+
+ if (uxa_screen->swappedOut || uxa_screen->force_fallback)
+ goto fallback;
+
+ if (!uxa_drawable_is_offscreen(pDst->pDrawable))
+ goto fallback;
+
+ if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
+ goto fallback;
+
+ /* Remove repeat in source if useless */
+ if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
+ transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
+ (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
+ drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
+ pSrc->repeat = 0;
+
+ if (!pMask) {
+ if (op == PictOpClear) {
+ PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
+ if (clear &&
+ uxa_try_driver_solid_fill(clear, pDst,
+ xSrc, ySrc,
+ xDst, yDst,
+ width, height) == 1)
+ goto done;
+ }
+
+ if (pSrc->pDrawable == NULL) {
+ if (pSrc->pSourcePict) {
+ SourcePict *source = pSrc->pSourcePict;
+ if (source->type == SourcePictTypeSolidFill) {
+ if (op == PictOpSrc ||
+ (op == PictOpOver &&
+ (source->solidFill.color & 0xff000000) == 0xff000000)) {
+ ret = uxa_try_driver_solid_fill(pSrc, pDst,
+ xSrc, ySrc,
+ xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+ }
+ }
+ } else if (pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat &&
+ (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
+ ret = uxa_try_driver_solid_fill(pSrc, pDst,
+ xSrc, ySrc,
+ xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ } else if (compatible_formats (op, pDst, pSrc) &&
+ pSrc->filter != PictFilterConvolution &&
+ transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
+ if (!pSrc->repeat &&
+ drawable_contains(pSrc->pDrawable,
+ xSrc + tx, ySrc + ty,
+ width, height)) {
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x + tx;
+ ySrc += pSrc->pDrawable->y + ty;
+
+ 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->repeat && pSrc->repeatType == RepeatNormal &&
+ pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
+ DDXPointRec patOrg;
+
+ /* Let's see if the driver can do the repeat
+ * in one go
+ */
+ if (uxa_screen->info->prepare_composite) {
+ 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 + tx;
+ ySrc += pSrc->pDrawable->y + ty;
+
+ 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->pDrawable && pMask->repeat &&
+ pMask->filter != PictFilterConvolution &&
+ transform_is_integer_translation(pMask->transform, &tx, &ty) &&
+ (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
+ drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
+ pMask->repeat = 0;
+
+ if (uxa_screen->info->prepare_composite) {
+ 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 ?
+ pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat :
+ pSrc->pSourcePict ?
+ pSrc->pSourcePict->type == SourcePictTypeSolidFill :
+ 0;
+
+ /* 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:
+ uxa_print_composite_fallback("uxa_composite",
+ op, pSrc, pMask, pDst);
+
+ 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;
+ int error;
+
+ 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,
+ UXA_CREATE_PIXMAP_FOR_MAP);
+ if (!pPixmap)
+ return 0;
+ 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 src, PicturePtr dst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntrap, xTrapezoid * traps)
+{
+ ScreenPtr screen = dst->pDrawable->pScreen;
+ BoxRec bounds;
+ Bool direct;
+
+ direct = op == PictOpAdd && miIsSolidAlpha(src);
+ 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 = dst->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;
+
+ if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
+ PictureScreenPtr ps = GetPictureScreen(screen);
+
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
+ uxa_finish_access(pDraw);
+ }
+ } else if (maskFormat) {
+ PixmapPtr scratch = NULL;
+ PicturePtr mask;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+ int width, height;
+ pixman_image_t *image;
+ pixman_format_code_t format;
+
+ xDst = traps[0].left.p1.x >> 16;
+ yDst = traps[0].left.p1.y >> 16;
+
+ width = bounds.x2 - bounds.x1;
+ height = bounds.y2 - bounds.y1;
+
+ format = maskFormat->format |
+ (BitsPerPixel(maskFormat->depth) << 24);
+ image =
+ pixman_image_create_bits(format, width, height, NULL, 0);
+ if (!image)
+ return;
+
+ for (; ntrap; ntrap--, traps++)
+ pixman_rasterize_trapezoid(image,
+ (pixman_trapezoid_t *) traps,
+ -bounds.x1, -bounds.y1);
+ if (uxa_drawable_is_offscreen(dst->pDrawable)) {
+ mask = uxa_picture_from_pixman_image(screen, image, format);
+ } else {
+ int error;
+
+ scratch = GetScratchPixmapHeader(screen, width, height,
+ PIXMAN_FORMAT_DEPTH(format),
+ PIXMAN_FORMAT_BPP(format),
+ pixman_image_get_stride(image),
+ pixman_image_get_data(image));
+ mask = CreatePicture(0, &scratch->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format),
+ format),
+ 0, 0, serverClient, &error);
+ }
+ if (!mask) {
+ if (scratch)
+ FreeScratchPixmapHeader(scratch);
+ pixman_image_unref(image);
+ return;
+ }
+
+ xRel = bounds.x1 + xSrc - xDst;
+ yRel = bounds.y1 + ySrc - yDst;
+ CompositePicture(op, src, mask, dst,
+ xRel, yRel,
+ 0, 0,
+ bounds.x1, bounds.y1,
+ width, height);
+ FreePicture(mask, 0);
+
+ if (scratch)
+ FreeScratchPixmapHeader(scratch);
+ pixman_image_unref(image);
+ } else {
+ if (dst->polyEdge == PolyEdgeSharp)
+ maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
+ else
+ maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
+ for (; ntrap; ntrap--, traps++)
+ uxa_trapezoids(op, src, dst, 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;
+ if (uxa_prepare_access(pDraw, UXA_ACCESS_RW)) {
+ (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+ uxa_finish_access(pDraw);
+ }
+ } else if (maskFormat) {
+ PicturePtr pPicture;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+ int width = bounds.x2 - bounds.x1;
+ int height = bounds.y2 - bounds.y1;
+ GCPtr pGC;
+ xRectangle rect;
+
+ xDst = tris[0].p1.x >> 16;
+ yDst = tris[0].p1.y >> 16;
+
+ pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
+ width, height);
+ if (!pPicture)
+ return;
+
+ /* Clear the alpha picture to 0. */
+ pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
+ if (!pGC) {
+ FreePicture(pPicture, 0);
+ return;
+ }
+ ValidateGC(pPicture->pDrawable, pGC);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
+ FreeScratchGC(pGC);
+
+ if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) {
+ (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
+ ntri, tris);
+ uxa_finish_access(pPicture->pDrawable);
+ }
+
+ 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/src/uxa/uxa-unaccel.c b/src/uxa/uxa-unaccel.c
new file mode 100644
index 0000000..15be821
--- /dev/null
+++ b/src/uxa/uxa-unaccel.c
@@ -0,0 +1,430 @@
+/*
+ *
+ * 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.
+ */
+Bool uxa_prepare_access_gc(GCPtr pGC)
+{
+ if (pGC->stipple)
+ if (!uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RO))
+ return FALSE;
+ if (pGC->fillStyle == FillTiled)
+ if (!uxa_prepare_access
+ (&pGC->tile.pixmap->drawable, UXA_ACCESS_RO)) {
+ if (pGC->stipple)
+ uxa_finish_access(&pGC->stipple->drawable);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * 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);
+ if (pGC->stipple)
+ uxa_finish_access(&pGC->stipple->drawable);
+}
+
+char uxa_drawable_location(DrawablePtr pDrawable)
+{
+ return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm';
+}
+
+void
+uxa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth,
+ fSorted);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+ uxa_finish_access(pDrawable);
+ }
+}
+
+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)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+ bits);
+ uxa_finish_access(pDrawable);
+ }
+}
+
+RegionPtr
+uxa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+ ScreenPtr screen = pSrc->pScreen;
+ RegionPtr ret = NULL;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc),
+ uxa_drawable_location(pDst)));
+ if (uxa_prepare_access(pDst, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(pSrc, UXA_ACCESS_RO)) {
+ ret =
+ fbCopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
+ dsty);
+ uxa_finish_access(pSrc);
+ }
+ uxa_finish_access(pDst);
+ }
+ 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)
+{
+ ScreenPtr screen = pSrc->pScreen;
+ RegionPtr ret = NULL;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc),
+ uxa_drawable_location(pDst)));
+ if (uxa_prepare_access(pDst, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(pSrc, UXA_ACCESS_RO)) {
+ ret =
+ fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx,
+ dsty, bitPlane);
+ uxa_finish_access(pSrc);
+ }
+ uxa_finish_access(pDst);
+ }
+ return ret;
+}
+
+void
+uxa_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ fbPolyPoint(pDrawable, pGC, mode, npt, pptInit);
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ 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) {
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPolyLine(pDrawable, pGC, mode, npt, ppt);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+ 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)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->lineWidth,
+ nsegInit));
+ if (pGC->lineWidth == 0) {
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPolySegment(pDrawable, pGC, nsegInit,
+ pSegInit);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+ 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)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ 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) {
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPolyArc(pDrawable, pGC, narcs, pArcs);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+ return;
+ }
+#endif
+ miPolyArc(pDrawable, pGC, narcs, pArcs);
+}
+
+void
+uxa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle * prect)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPolyFillRect(pDrawable, pGC, nrect, prect);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+ pglyphBase);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr * ppci, pointer pglyphBase)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->fillStyle,
+ pGC->alu));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci,
+ pglyphBase);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
+ uxa_drawable_location(&pBitmap->drawable),
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(&pBitmap->drawable, UXA_ACCESS_RO)) {
+ if (uxa_prepare_access_gc(pGC)) {
+ fbPushPixels(pGC, pBitmap, pDrawable, w, h, x,
+ y);
+ uxa_finish_access_gc(pGC);
+ }
+ uxa_finish_access(&pBitmap->drawable);
+ }
+ uxa_finish_access(pDrawable);
+ }
+}
+
+void
+uxa_check_get_spans(DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
+{
+ ScreenPtr screen = pDrawable->pScreen;
+
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ if (uxa_prepare_access(pDrawable, UXA_ACCESS_RO)) {
+ fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ uxa_finish_access(pDrawable);
+ }
+}
+
+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)
+{
+ ScreenPtr screen = pDst->pDrawable->pScreen;
+
+ UXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
+
+ if (uxa_prepare_access(pDst->pDrawable, UXA_ACCESS_RW)) {
+ if (pSrc->pDrawable == NULL ||
+ uxa_prepare_access(pSrc->pDrawable, UXA_ACCESS_RO)) {
+ if (!pMask || pMask->pDrawable == NULL ||
+ uxa_prepare_access(pMask->pDrawable, UXA_ACCESS_RO))
+ {
+ fbComposite(op, pSrc, pMask, pDst,
+ xSrc, ySrc,
+ xMask, yMask,
+ xDst, yDst,
+ width, height);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_finish_access(pMask->pDrawable);
+ }
+ if (pSrc->pDrawable != NULL)
+ uxa_finish_access(pSrc->pDrawable);
+ }
+ uxa_finish_access(pDst->pDrawable);
+ }
+}
+
+void
+uxa_check_add_traps(PicturePtr pPicture,
+ INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
+{
+ ScreenPtr screen = pPicture->pDrawable->pScreen;
+
+ UXA_FALLBACK(("to pict %p (%c)\n", pPicture,
+ uxa_drawable_location(pPicture->pDrawable)));
+ if (uxa_prepare_access(pPicture->pDrawable, UXA_ACCESS_RW)) {
+ fbAddTraps(pPicture, x_off, y_off, ntrap, traps);
+ uxa_finish_access(pPicture->pDrawable);
+ }
+}
+
+/**
+ * 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;
+
+ if (!uxa_prepare_access(&pPixmap->drawable, UXA_ACCESS_RO))
+ return 0;
+
+ 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);
+
+ return pixel;
+}
diff --git a/src/uxa/uxa.c b/src/uxa/uxa.c
new file mode 100644
index 0000000..b661bb8
--- /dev/null
+++ b/src/uxa/uxa.c
@@ -0,0 +1,579 @@
+/*
+ * 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"
+
+int uxa_screen_index;
+
+/**
+ * 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->pixmap_is_offscreen)
+ return uxa_screen->info->pixmap_is_offscreen(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.
+ */
+Bool uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access)
+{
+ 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 TRUE;
+
+ if (uxa_screen->info->prepare_access)
+ return (*uxa_screen->info->prepare_access) (pPixmap, access);
+ return TRUE;
+}
+
+/**
+ * uxa_finish_access() is UXA's wrapper for the driver's finish_access() handler.
+ *
+ * It deals with calling the driver's finish_access() only if necessary.
+ */
+void uxa_finish_access(DrawablePtr pDrawable)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable);
+
+ if (uxa_screen->info->finish_access == NULL)
+ return;
+
+ if (!uxa_pixmap_is_offscreen(pPixmap))
+ return;
+
+ (*uxa_screen->info->finish_access) (pPixmap);
+}
+
+/**
+ * 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/finish_access.
+ */
+#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.
+ */
+ if (uxa_prepare_access
+ (&pOldTile->drawable, UXA_ACCESS_RO)) {
+ pNewTile =
+ fb24_32ReformatTile(pOldTile,
+ pDrawable->
+ bitsPerPixel);
+ uxa_finish_access(&pOldTile->drawable);
+ }
+ }
+ 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)) {
+ if (uxa_prepare_access
+ (&pGC->tile.pixmap->drawable, UXA_ACCESS_RW)) {
+ fbPadPixmap(pGC->tile.pixmap);
+ uxa_finish_access(&pGC->tile.pixmap->drawable);
+ }
+ }
+ /* Mask out the GCTile change notification, now that we've
+ * done FB's job for it.
+ */
+ changes &= ~GCTile;
+ }
+
+ if (changes & GCStipple && pGC->stipple) {
+ /* We can't inline stipple handling like we do for GCTile
+ * because it sets fbgc privates.
+ */
+ if (uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RW)) {
+ fbValidateGC(pGC, changes, pDrawable);
+ uxa_finish_access(&pGC->stipple->drawable);
+ }
+ } else {
+ fbValidateGC(pGC, changes, pDrawable);
+ }
+
+ 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;
+}
+
+Bool uxa_prepare_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap) {
+ if (!uxa_prepare_access
+ (&pWin->background.pixmap->drawable, UXA_ACCESS_RO))
+ return FALSE;
+ }
+
+ if (pWin->borderIsPixel == FALSE) {
+ if (!uxa_prepare_access
+ (&pWin->border.pixmap->drawable, UXA_ACCESS_RO)) {
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_finish_access(&pWin->background.pixmap->
+ drawable);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void uxa_finish_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_finish_access(&pWin->background.pixmap->drawable);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_finish_access(&pWin->border.pixmap->drawable);
+}
+
+static Bool uxa_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+ Bool ret;
+
+ if (!uxa_prepare_access_window(pWin))
+ return FALSE;
+ ret = fbChangeWindowAttributes(pWin, mask);
+ uxa_finish_access_window(pWin);
+ return ret;
+}
+
+static RegionPtr uxa_bitmap_to_region(PixmapPtr pPix)
+{
+ RegionPtr ret;
+ if (!uxa_prepare_access(&pPix->drawable, UXA_ACCESS_RO))
+ return NULL;
+ ret = fbPixmapToRegion(pPix);
+ uxa_finish_access(&pPix->drawable);
+ return ret;
+}
+
+static void uxa_xorg_enable_disable_fb_access(int index, Bool enable)
+{
+ ScreenPtr screen = screenInfo.screens[index];
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+
+ if (!enable && uxa_screen->disableFbCount++ == 0)
+ uxa_screen->swappedOut = TRUE;
+
+ if (enable && --uxa_screen->disableFbCount == 0)
+ uxa_screen->swappedOut = FALSE;
+
+ if (uxa_screen->SavedEnableDisableFBAccess)
+ uxa_screen->SavedEnableDisableFBAccess(index, enable);
+}
+
+void uxa_set_fallback_debug(ScreenPtr screen, Bool enable)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+
+ uxa_screen->fallback_debug = enable;
+}
+
+void uxa_set_force_fallback(ScreenPtr screen, Bool value)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(screen);
+
+ uxa_screen->force_fallback = value;
+}
+
+/**
+ * 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);
+ ScrnInfoPtr scrn = xf86Screens[pScreen->myNum];
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+ int n;
+
+ if (uxa_screen->solid_clear)
+ FreePicture(uxa_screen->solid_clear, 0);
+ if (uxa_screen->solid_black)
+ FreePicture(uxa_screen->solid_black, 0);
+ if (uxa_screen->solid_white)
+ FreePicture(uxa_screen->solid_white, 0);
+ for (n = 0; n < uxa_screen->solid_cache_size; n++)
+ FreePicture(uxa_screen->solid_cache[n].picture, 0);
+
+ 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;
+ scrn->EnableDisableFBAccess = uxa_screen->SavedEnableDisableFBAccess;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = uxa_screen->SavedComposite;
+ ps->CompositeRects = uxa_screen->SavedCompositeRects;
+ ps->Glyphs = uxa_screen->SavedGlyphs;
+ ps->Trapezoids = uxa_screen->SavedTrapezoids;
+ ps->AddTraps = uxa_screen->SavedAddTraps;
+ ps->Triangles = uxa_screen->SavedTriangles;
+
+ ps->UnrealizeGlyph = uxa_screen->SavedUnrealizeGlyph;
+ }
+#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;
+ ScrnInfoPtr scrn = xf86Screens[screen->myNum];
+
+ 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->prepare_solid) {
+ LogMessage(X_ERROR,
+ "UXA(%d): uxa_driver_t::prepare_solid must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->prepare_copy) {
+ LogMessage(X_ERROR,
+ "UXA(%d): uxa_driver_t::prepare_copy must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+ 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_index, uxa_screen);
+
+ uxa_screen->force_fallback = FALSE;
+
+ uxa_screen->solid_cache_size = 0;
+ uxa_screen->solid_clear = 0;
+ uxa_screen->solid_black = 0;
+ uxa_screen->solid_white = 0;
+
+// 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;
+
+ uxa_screen->SavedEnableDisableFBAccess = scrn->EnableDisableFBAccess;
+ scrn->EnableDisableFBAccess = uxa_xorg_enable_disable_fb_access;
+
+#ifdef RENDER
+ {
+ PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+ if (ps) {
+ uxa_screen->SavedComposite = ps->Composite;
+ ps->Composite = uxa_composite;
+
+ uxa_screen->SavedCompositeRects = ps->CompositeRects;
+ ps->CompositeRects = uxa_solid_rects;
+
+ uxa_screen->SavedGlyphs = ps->Glyphs;
+ ps->Glyphs = uxa_glyphs;
+
+ uxa_screen->SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+ ps->UnrealizeGlyph = uxa_glyph_unrealize;
+
+ 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
+
+ if (!uxa_glyphs_init(screen))
+ return FALSE;
+
+ LogMessage(X_INFO,
+ "UXA(%d): Driver registered support for the following"
+ " operations:\n", screen->myNum);
+ assert(uxa_driver->prepare_solid != NULL);
+ LogMessage(X_INFO, " solid\n");
+ assert(uxa_driver->prepare_copy != NULL);
+ LogMessage(X_INFO, " copy\n");
+ if (uxa_driver->prepare_composite != NULL) {
+ LogMessage(X_INFO, " composite (RENDER acceleration)\n");
+ }
+ if (uxa_driver->put_image != NULL) {
+ LogMessage(X_INFO, " put_image\n");
+ }
+ if (uxa_driver->get_image != NULL) {
+ LogMessage(X_INFO, " get_image\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 */
+}
diff --git a/src/uxa/uxa.h b/src/uxa/uxa.h
new file mode 100644
index 0000000..cb08665
--- /dev/null
+++ b/src/uxa/uxa.h
@@ -0,0 +1,583 @@
+/*
+ * 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
+
+typedef enum {
+ UXA_ACCESS_RO,
+ UXA_ACCESS_RW
+} uxa_access_t;
+
+/**
+ * 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;
+
+ /** @name solid
+ * @{
+ */
+ /**
+ * check_solid() checks whether the driver can do a solid fill to this drawable.
+ * @param pDrawable Destination drawable
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ *
+ * The check_solid() call is recommended if prepare_solid() is
+ * implemented, but is not required.
+ */
+ Bool(*check_solid) (DrawablePtr pDrawable, int alu, Pixel planemask);
+
+ /**
+ * prepare_solid() 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 prepare_solid() call is required of all drivers, but it may fail
+ * for any reason. Failure results in a fallback to software rendering.
+ */
+ Bool(*prepare_solid) (PixmapPtr pPixmap,
+ int alu, Pixel planemask, Pixel fg);
+
+ /**
+ * solid() performs a solid fill set up in the last prepare_solid()
+ * 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 prepare_solid() 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 prepare_solid() ever succeeds.
+ */
+ void (*solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
+
+ /**
+ * done_solid() finishes a set of solid fills.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The done_solid() call is called at the end of a series of consecutive
+ * solid() calls following a successful prepare_solid(). This allows
+ * drivers to finish up emitting drawing commands that were buffered, or
+ * clean up state from prepare_solid().
+ *
+ * This call is required if prepare_solid() ever succeeds.
+ */
+ void (*done_solid) (PixmapPtr pPixmap);
+ /** @} */
+
+ /** @name copy
+ * @{
+ */
+ /**
+ * check_copy() checks whether the driver can blit between the two Pictures
+ */
+ Bool(*check_copy) (PixmapPtr pSrc, PixmapPtr pDst, int alu, Pixel planemask);
+ /**
+ * prepare_copy() 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 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 prepare_copy() call is required of all drivers, but it may fail
+ * for any reason. Failure results in a fallback to software rendering.
+ */
+ Bool(*prepare_copy) (PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ int dx, int dy, int alu, Pixel planemask);
+
+ /**
+ * copy() performs a copy set up in the last prepare_copy 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 prepare_copy() 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 prepare_copy(). 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 prepare_copy ever succeeds.
+ */
+ void (*copy) (PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY, int dstX, int dstY, int width, int height);
+
+ /**
+ * done_copy() finishes a set of copies.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The done_copy() call is called at the end of a series of consecutive
+ * copy() calls following a successful prepare_copy(). This allows
+ * drivers to finish up emitting drawing commands that were buffered,
+ * or clean up state from prepare_copy().
+ *
+ * This call is required if prepare_copy() ever succeeds.
+ */
+ void (*done_copy) (PixmapPtr pDstPixmap);
+ /** @} */
+
+ /** @name composite
+ * @{
+ */
+ /**
+ * check_composite() 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
+ * @param width The width of the composite operation
+ * @param height The height of the composite operation
+ *
+ * The check_composite() 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.
+ *
+ * See prepare_composite() for more details on likely issues that
+ * drivers will have in accelerating composite operations.
+ *
+ * The check_composite() call is recommended if prepare_composite() is
+ * implemented, but is not required.
+ */
+ Bool(*check_composite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ int width, int height);
+
+ /**
+ * check_composite_target() checks to see if the destination of the composite
+ * operation can be used without midification.
+ *
+ * @param pixmap Destination Pixmap
+ *
+ * The check_composite_target() call is recommended if prepare_composite() is
+ * implemented, but is not required.
+ */
+ Bool(*check_composite_target) (PixmapPtr pixmap);
+
+ /**
+ * check_composite_texture() checks to see if a source to the composite
+ * operation can be used without midification.
+ *
+ * @param pScreen Screen
+ * @param pPicture Picture
+ *
+ * The check_composite_texture() call is recommended if prepare_composite() is
+ * implemented, but is not required.
+ */
+ Bool(*check_composite_texture) (ScreenPtr pScreen,
+ PicturePtr pPicture);
+
+ /**
+ * prepare_composite() 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 prepare_composite 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 prepare_composite() 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(*prepare_composite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask, PixmapPtr pDst);
+
+ /**
+ * composite() performs a composite operation set up in the last
+ * prepare_composite() 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
+ * prepare_composite() 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 prepare_composite() ever succeeds.
+ */
+ void (*composite) (PixmapPtr pDst,
+ int srcX,
+ int srcY,
+ int maskX,
+ int maskY,
+ int dstX, int dstY, int width, int height);
+
+ /**
+ * done_composite() finishes a set of composite operations.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The done_composite() call is called at the end of a series of
+ * consecutive composite() calls following a successful
+ * prepare_composite(). This allows drivers to finish up emitting
+ * drawing commands that were buffered, or clean up state from
+ * prepare_composite().
+ *
+ * This call is required if prepare_composite() ever succeeds.
+ */
+ void (*done_composite) (PixmapPtr pDst);
+ /** @} */
+
+ /**
+ * put_image() 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.
+ *
+ * put_image() 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.
+ *
+ * put_image() 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.
+ *
+ * put_image() is not required, but is recommended if composite
+ * acceleration is supported.
+ */
+ Bool(*put_image) (PixmapPtr pDst,
+ int x,
+ int y, int w, int h, char *src, int src_pitch);
+
+ /**
+ * get_image() 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.
+ *
+ * get_image() 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.
+ *
+ * @return TRUE if the driver successfully downloaded the data. FALSE
+ * indicates that UXA should fall back to doing the download in
+ * software.
+ *
+ * get_image() is not required, but is highly recommended.
+ */
+ Bool(*get_image) (PixmapPtr pSrc,
+ int x, int y,
+ int w, int h, char *dst, int dst_pitch);
+
+ /** @{ */
+ /**
+ * prepare_access() is called before CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * prepare_access() 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 prepare_access() called on them
+ * per operation, drivers can have a small, statically-allocated space
+ * to maintain state for prepare_access() and finish_access() in.
+ * Note that the same pixmap may have prepare_access() called on it
+ * more than once, for uxample when doing a copy within the same
+ * pixmap (so it gets prepare_access as
+ * #UXA_PREPARE_DEST and then as #UXA_PREPARE_SRC).
+ *
+ * prepare_access() may fail. An example might be the case of
+ * hardware that can set up 1 or 2 surfaces for CPU access, but not
+ * 3. If prepare_access()
+ * fails, UXA will migrate the pixmap to system memory.
+ * get_image() must be implemented and must not fail if a driver
+ * wishes to fail in prepare_access(). prepare_access() must not
+ * fail when pPix is the visible screen, because the visible screen
+ * can not be migrated.
+ *
+ * @return TRUE if prepare_access() successfully prepared the pixmap
+ * for CPU drawing.
+ * @return FALSE if prepare_access() is unsuccessful and UXA should use
+ * get_image() to migate the pixmap out.
+ */
+ Bool(*prepare_access) (PixmapPtr pPix, uxa_access_t access);
+
+ /**
+ * finish_access() is called after CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * finish_access() will be called after finishing CPU access of an
+ * offscreen pixmap set up by prepare_access(). Note that the
+ * finish_access() will not be called if prepare_access() failed.
+ */
+ void (*finish_access) (PixmapPtr pPix);
+
+ /**
+ * 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
+ * prepare_access()/finish_access() when accessing it with the CPU.
+ */
+ Bool(*pixmap_is_offscreen) (PixmapPtr pPix);
+
+ /** @} */
+} 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)
+
+/** @} */
+
+/** @name UXA CreatePixmap hint flags
+ * @{
+ */
+/**
+ * Flag to hint that the first operation on the pixmap will be a
+ * prepare_access.
+ */
+#define UXA_CREATE_PIXMAP_FOR_MAP 0x20000000
+/** @} */
+
+uxa_driver_t *uxa_driver_alloc(void);
+
+Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver);
+
+void uxa_driver_fini(ScreenPtr pScreen);
+
+CARD32 uxa_get_pixmap_first_pixel(PixmapPtr pPixmap);
+
+Bool
+uxa_get_color_for_pixmap (PixmapPtr pixmap,
+ CARD32 src_format,
+ CARD32 dst_format,
+ CARD32 *pixel);
+
+void uxa_set_fallback_debug(ScreenPtr screen, Bool enable);
+void uxa_set_force_fallback(ScreenPtr screen, Bool enable);
+
+/**
+ * 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 */