summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am6
-rw-r--r--src/i830.h16
-rw-r--r--src/i830_accel.c31
-rw-r--r--src/i830_debug.c2
-rw-r--r--src/i830_dri.c2
-rw-r--r--src/i830_driver.c153
-rw-r--r--src/i830_exa.c131
-rw-r--r--src/i830_memory.c16
-rw-r--r--src/i830_video.c4
-rw-r--r--uxa/Makefile.am20
-rw-r--r--uxa/uxa-accel.c1038
-rw-r--r--uxa/uxa-glyphs.c880
-rw-r--r--uxa/uxa-priv.h444
-rw-r--r--uxa/uxa-render.c1052
-rw-r--r--uxa/uxa-unaccel.c370
-rw-r--r--uxa/uxa.c573
-rw-r--r--uxa/uxa.h671
19 files changed, 5334 insertions, 78 deletions
diff --git a/Makefile.am b/Makefile.am
index b2398a88..5db07de9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,7 +19,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AUTOMAKE_OPTIONS = foreign
-SUBDIRS = src man
+SUBDIRS = uxa src man
EXTRA_DIST = README
DISTCLEANFILES = doltcompile
diff --git a/configure.ac b/configure.ac
index db16c356..b24a1541 100644
--- a/configure.ac
+++ b/configure.ac
@@ -251,6 +251,7 @@ XORG_CHECK_LINUXDOC
AC_OUTPUT([
Makefile
+ uxa/Makefile
src/Makefile
src/xvmc/Makefile
src/bios_reader/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 2932233d..dd92c8d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,13 +31,13 @@ SUBDIRS = xvmc bios_reader ch7017 ch7xxx ivch sil164 tfp410 $(REGDUMPER)
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
AM_CFLAGS = @WARN_CFLAGS@ @XORG_CFLAGS@ @DRM_CFLAGS@ @DRI_CFLAGS@ \
- @PCIACCESS_CFLAGS@ \
- @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA
+ @PCIACCESS_CFLAGS@ -I../uxa \
+ @XMODES_CFLAGS@ -DI830_XV -DI830_USE_XAA -DI830_USE_EXA -DI830_USE_UXA
intel_drv_la_LTLIBRARIES = intel_drv.la
intel_drv_la_LDFLAGS = -module -avoid-version
intel_drv_ladir = @moduledir@/drivers
-intel_drv_la_LIBADD = -lm
+intel_drv_la_LIBADD = -lm ../uxa/libuxa.la
if XSERVER_LIBPCIACCESS
intel_drv_la_LIBADD += @PCIACCESS_LIBS@
endif
diff --git a/src/i830.h b/src/i830.h
index a8ab8c6c..2fb8efaa 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -83,7 +83,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef I830_USE_EXA
#include "exa.h"
+#include "uxa.h"
Bool I830EXAInit(ScreenPtr pScreen);
+Bool i830_uxa_init(ScreenPtr pScreen);
unsigned long long I830TexOffsetStart(PixmapPtr pPix);
#endif
@@ -355,6 +357,14 @@ enum backlight_control {
BCM_KERNEL,
};
+typedef enum accel_method {
+ ACCEL_UNINIT = 0,
+ ACCEL_NONE,
+ ACCEL_XAA,
+ ACCEL_EXA,
+ ACCEL_UXA
+} accel_method_t;
+
typedef struct _I830Rec {
unsigned char *MMIOBase;
unsigned char *GTTBase;
@@ -496,8 +506,7 @@ typedef struct _I830Rec {
Bool fence_used[FENCE_NEW_NR];
- Bool useEXA;
- Bool noAccel;
+ accel_method_t accel;
Bool SWCursor;
#ifdef I830_USE_XAA
XAAInfoRecPtr AccelInfoRec;
@@ -518,6 +527,7 @@ typedef struct _I830Rec {
#ifdef I830_USE_EXA
ExaDriverPtr EXADriverPtr;
+ uxa_driver_t *uxa_driver;
PixmapPtr pSrcPixmap;
#endif
@@ -902,7 +912,7 @@ static inline int i830_fb_compression_supported(I830Ptr pI830)
/* fbc depends on tiled surface. And we don't support tiled
* front buffer with XAA now.
*/
- if (!pI830->tiling || (IS_I965G(pI830) && !pI830->useEXA))
+ if (!pI830->tiling || (IS_I965G(pI830) && pI830->accel <= ACCEL_XAA))
return FALSE;
return TRUE;
}
diff --git a/src/i830_accel.c b/src/i830_accel.c
index c3cd08e0..579de31c 100644
--- a/src/i830_accel.c
+++ b/src/i830_accel.c
@@ -67,12 +67,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
unsigned long
intel_get_pixmap_offset(PixmapPtr pPix)
{
+#ifdef I830_USE_EXA
ScreenPtr pScreen = pPix->drawable.pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
-#ifdef I830_USE_EXA
- if (pI830->useEXA)
+ if (pI830->accel == ACCEL_EXA)
return exaGetPixmapOffset(pPix);
#endif
return (unsigned long)pPix->devPrivate.ptr - (unsigned long)pI830->FbBase;
@@ -81,17 +81,15 @@ intel_get_pixmap_offset(PixmapPtr pPix)
unsigned long
intel_get_pixmap_pitch(PixmapPtr pPix)
{
+#ifdef I830_USE_EXA
ScreenPtr pScreen = pPix->drawable.pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
-#ifdef I830_USE_EXA
- if (pI830->useEXA)
+ if (pI830->accel == ACCEL_EXA)
return exaGetPixmapPitch(pPix);
#endif
-#ifdef I830_USE_XAA
return (unsigned long)pPix->devKind;
-#endif
}
int
@@ -151,6 +149,9 @@ I830WaitLpRing(ScrnInfoPtr pScrn, int n, int timeout_millis)
#ifdef I830_USE_EXA
pI830->EXADriverPtr = NULL;
#endif
+#ifdef I830_USE_UXA
+ pI830->uxa_driver = NULL;
+#endif
FatalError("lockup\n");
}
@@ -176,7 +177,7 @@ I830Sync(ScrnInfoPtr pScrn)
if (I810_DEBUG & (DEBUG_VERBOSE_ACCEL | DEBUG_VERBOSE_SYNC))
ErrorF("I830Sync\n");
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
#ifdef XF86DRI
@@ -278,15 +279,25 @@ I830SelectBuffer(ScrnInfoPtr pScrn, int buffer)
Bool
I830AccelInit(ScreenPtr pScreen)
{
-#ifdef I830_USE_EXA
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
- if (pI830->useEXA)
+ switch (pI830->accel) {
+#ifdef I830_USE_UXA
+ case ACCEL_UXA:
+ return i830_uxa_init(pScreen);
+#endif
+#ifdef I830_USE_EXA
+ case ACCEL_EXA:
return I830EXAInit(pScreen);
#endif
#ifdef I830_USE_XAA
- return I830XAAInit(pScreen);
+ case ACCEL_XAA:
+ return I830XAAInit(pScreen);
#endif
+ case ACCEL_UNINIT:
+ case ACCEL_NONE:
+ break;
+ }
return FALSE;
}
diff --git a/src/i830_debug.c b/src/i830_debug.c
index 1671e255..f1205cc6 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -1314,6 +1314,8 @@ i830_valid_command (uint32_t cmd)
if (!mi_cmds[opcode])
return -1;
break;
+ case 1:
+ return -1;
case 2: /* 2D */
count = (cmd & 0x1f) + 2;
opcode = (cmd >> 22) & 0x7f;
diff --git a/src/i830_dri.c b/src/i830_dri.c
index 46783721..0e5d81dd 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -589,7 +589,7 @@ I830DRIScreenInit(ScreenPtr pScreen)
#if DRIINFO_MAJOR_VERSION > 5 || \
(DRIINFO_MAJOR_VERSION == 5 && DRIINFO_MINOR_VERSION >= 3)
- if (pI830->useEXA)
+ if (pI830->accel == ACCEL_EXA)
pDRIInfo->texOffsetStart = I830TexOffsetStart;
#endif
diff --git a/src/i830_driver.c b/src/i830_driver.c
index b6fac9f8..ed974ce2 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -290,9 +290,7 @@ static PciChipsets I830PciChipsets[] = {
*/
typedef enum {
-#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
OPTION_ACCELMETHOD,
-#endif
OPTION_NOACCEL,
OPTION_SW_CURSOR,
OPTION_CACHE_LINES,
@@ -318,9 +316,7 @@ typedef enum {
} I830Opts;
static OptionInfoRec I830Options[] = {
-#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
{OPTION_ACCELMETHOD, "AccelMethod", OPTV_ANYSTR, {0}, FALSE},
-#endif
{OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE},
@@ -1338,6 +1334,15 @@ i830_detect_chipset(ScrnInfoPtr pScrn)
return TRUE;
}
+static const char *accel_name[] =
+{
+ "unspecified",
+ "no",
+ "XAA",
+ "EXA",
+ "UXA",
+};
+
/**
* This is called per zaphod head (so usually just once) to do initialization
* before the Screen is created.
@@ -1554,7 +1559,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
num_pipe, num_pipe > 1 ? "s" : "");
if (xf86ReturnOptValBool(pI830->Options, OPTION_NOACCEL, FALSE)) {
- pI830->noAccel = TRUE;
+ pI830->accel = ACCEL_NONE;
}
/*
@@ -1568,29 +1573,38 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
* All this *could* go away if we removed XAA support from this driver,
* for example. :)
*/
- if (!pI830->noAccel) {
+ if (pI830->accel == ACCEL_UNINIT) {
+ pI830->accel = ACCEL_NONE;
+#ifdef I830_USE_XAA
+ pI830->accel = ACCEL_XAA;
+#endif
#ifdef I830_USE_EXA
- pI830->useEXA = TRUE;
-#else
- pI830->useEXA = FALSE;
+ pI830->accel = ACCEL_EXA;
+#endif
+#ifdef I830_USE_UXA
+ pI830->accel = ACCEL_UXA;
#endif
-#if defined(I830_USE_XAA) && defined(I830_USE_EXA)
+#if I830_USE_XAA + I830_USE_EXA + I830_USE_UXA >= 2
from = X_DEFAULT;
if ((s = (char *)xf86GetOptValString(pI830->Options,
OPTION_ACCELMETHOD))) {
if (!xf86NameCmp(s, "EXA")) {
from = X_CONFIG;
- pI830->useEXA = TRUE;
+ pI830->accel = ACCEL_EXA;
}
else if (!xf86NameCmp(s, "XAA")) {
from = X_CONFIG;
- pI830->useEXA = FALSE;
+ pI830->accel = ACCEL_XAA;
+ }
+ else if (!xf86NameCmp(s, "UXA")) {
+ from = X_CONFIG;
+ pI830->accel = ACCEL_UXA;
}
}
#endif
- xf86DrvMsg(pScrn->scrnIndex, from, "Using %s for acceleration\n",
- pI830->useEXA ? "EXA" : "XAA");
}
+ xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration\n",
+ accel_name[pI830->accel]);
if (xf86ReturnOptValBool(pI830->Options, OPTION_SW_CURSOR, FALSE)) {
pI830->SWCursor = TRUE;
@@ -1601,7 +1615,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
#ifdef XF86DRI
if (!pI830->directRenderingDisabled) {
- if (pI830->noAccel || pI830->SWCursor) {
+ if (pI830->accel == ACCEL_NONE || pI830->SWCursor) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it "
"needs HW cursor and 2D acceleration.\n");
pI830->directRenderingDisabled = TRUE;
@@ -1774,7 +1788,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
if (!IS_I965G(pI830) && pScrn->virtualY > 2048) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot support > 2048 vertical lines. disabling acceleration.\n");
- pI830->noAccel = TRUE;
+ pI830->accel = ACCEL_NONE;
}
/* Set display resolution */
@@ -1788,18 +1802,19 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
xf86LoaderReqSymLists(I810fbSymbols, NULL);
+ switch (pI830->accel) {
#ifdef I830_USE_XAA
- if (!pI830->noAccel && !pI830->useEXA) {
+ case ACCEL_XAA:
if (!xf86LoadSubModule(pScrn, "xaa")) {
PreInitCleanup(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(I810xaaSymbols, NULL);
- }
+ break;
#endif
#ifdef I830_USE_EXA
- if (!pI830->noAccel && pI830->useEXA) {
+ case ACCEL_EXA: {
XF86ModReqInfo req;
int errmaj, errmin;
@@ -1817,8 +1832,12 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
return FALSE;
}
xf86LoaderReqSymLists(I830exaSymbols, NULL);
+ break;
}
#endif
+ default:
+ break;
+ }
if (!pI830->SWCursor) {
if (!xf86LoadSubModule(pScrn, "ramdac")) {
PreInitCleanup(pScrn);
@@ -1878,7 +1897,7 @@ i830_stop_ring(ScrnInfoPtr pScrn, Bool flush)
pI830->entityPrivate->RingRunning = 0;
/* Flush the ring buffer (if enabled), then disable it. */
- if (!pI830->noAccel) {
+ if (pI830->accel != ACCEL_NONE) {
temp = INREG(LP_RING + RING_LEN);
if (temp & RING_VALID) {
i830_refresh_ring(pScrn);
@@ -1900,7 +1919,7 @@ i830_start_ring(ScrnInfoPtr pScrn)
DPRINTF(PFX, "SetRingRegs\n");
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
if (!I830IsPrimary(pScrn)) return;
@@ -2441,7 +2460,7 @@ IntelEmitInvarientState(ScrnInfoPtr pScrn)
I830Ptr pI830 = I830PTR(pScrn);
uint32_t ctx_addr;
- if (pI830->noAccel)
+ if (pI830->accel == ACCEL_NONE)
return;
#ifdef XF86DRI
@@ -2496,12 +2515,12 @@ I830BlockHandler(int i,
pI830->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = I830BlockHandler;
- if (pScrn->vtSema && !pI830->noAccel) {
+ if (pScrn->vtSema && pI830->accel != ACCEL_NONE) {
/* Emit a flush of the rendering cache, or on the 965 and beyond
* rendering results may not hit the framebuffer until significantly
* later.
*/
- if (!pI830->noAccel && (pI830->need_mi_flush || pI830->batch_used))
+ if (pI830->accel != ACCEL_NONE && (pI830->need_mi_flush || pI830->batch_used))
I830EmitFlush(pScrn);
/* Flush the batch, so that any rendering is executed in a timely
@@ -3001,12 +3020,12 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
pI830->XvEnabled = !pI830->XvDisabled;
if (pI830->XvEnabled) {
if (!I830IsPrimary(pScrn)) {
- if (!pI8301->XvEnabled || pI830->noAccel) {
+ if (!pI8301->XvEnabled || pI830->accel == ACCEL_NONE) {
pI830->XvEnabled = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled.\n");
}
} else
- if (pI830->noAccel || pI830->StolenOnly) {
+ if (pI830->accel == ACCEL_NONE || pI830->StolenOnly) {
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it "
"needs 2D accel and AGPGART.\n");
pI830->XvEnabled = FALSE;
@@ -3016,18 +3035,18 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
pI830->XvEnabled = FALSE;
#endif
- if (!pI830->noAccel) {
+ if (pI830->accel != ACCEL_NONE) {
if (pI830->memory_manager == NULL && pI830->LpRing->mem->size == 0) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling acceleration because the ring buffer "
"allocation failed.\n");
- pI830->noAccel = TRUE;
+ pI830->accel = ACCEL_NONE;
}
}
#ifdef I830_XV
if (pI830->XvEnabled) {
- if (pI830->noAccel) {
+ if (pI830->accel == ACCEL_NONE) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because it "
"needs 2D acceleration.\n");
pI830->XvEnabled = FALSE;
@@ -3049,7 +3068,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
*/
if (pI830->directRenderingEnabled) {
- if (pI830->noAccel || pI830->SWCursor || (pI830->StolenOnly && I830IsPrimary(pScrn))) {
+ if (pI830->accel == ACCEL_NONE || pI830->SWCursor || (pI830->StolenOnly && I830IsPrimary(pScrn))) {
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it "
"needs HW cursor, 2D accel and AGPGART.\n");
pI830->directRenderingEnabled = FALSE;
@@ -3123,7 +3142,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
DPRINTF(PFX, "assert( if(!I830EnterVT(scrnIndex, 0)) )\n");
- if (!pI830->useEXA) {
+ if (pI830->accel <= ACCEL_XAA) {
if (I830IsPrimary(pScrn)) {
if (!I830InitFBManager(pScreen, &(pI830->FbMemBox))) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
@@ -3171,7 +3190,7 @@ I830ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
DPRINTF(PFX,
"assert( if(!I830InitFBManager(pScreen, &(pI830->FbMemBox))) )\n");
- if (!pI830->noAccel) {
+ if (pI830->accel != ACCEL_NONE) {
if (!I830AccelInit(pScreen)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Hardware acceleration initialization failed\n");
@@ -3596,12 +3615,19 @@ I830CloseScreen(int scrnIndex, ScreenPtr pScreen)
}
#endif
#ifdef I830_USE_EXA
- if (pI830->useEXA && pI830->EXADriverPtr) {
+ if (pI830->EXADriverPtr) {
exaDriverFini(pScreen);
xfree(pI830->EXADriverPtr);
pI830->EXADriverPtr = NULL;
}
#endif
+#ifdef I830_USE_UXA
+ if (pI830->uxa_driver) {
+ uxa_driver_fini (pScreen);
+ xfree (pI830->uxa_driver);
+ pI830->uxa_driver = NULL;
+ }
+#endif
xf86_cursors_fini (pScreen);
i830_allocator_fini(pScrn);
@@ -3830,19 +3856,34 @@ i830WaitSync(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
+ switch (pI830->accel) {
#ifdef I830_USE_XAA
- if (!pI830->noAccel && !pI830->useEXA && pI830->AccelInfoRec
- && pI830->AccelInfoRec->NeedToSync) {
- (*pI830->AccelInfoRec->Sync)(pScrn);
- pI830->AccelInfoRec->NeedToSync = FALSE;
- }
+ case ACCEL_XAA:
+ if (pI830->AccelInfoRec && pI830->AccelInfoRec->NeedToSync) {
+ (*pI830->AccelInfoRec->Sync)(pScrn);
+ pI830->AccelInfoRec->NeedToSync = FALSE;
+ }
+ break;
#endif
#ifdef I830_USE_EXA
- if (!pI830->noAccel && pI830->useEXA && pI830->EXADriverPtr) {
- ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
- exaWaitSync(pScreen);
- }
+ case ACCEL_EXA:
+ if (pI830->EXADriverPtr) {
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ exaWaitSync(pScreen);
+ }
+ break;
#endif
+#ifdef I830_USE_UXA
+ case ACCEL_UXA:
+ if (pI830->uxa_driver) {
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ uxa_wait_sync(pScreen);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
}
void
@@ -3850,16 +3891,32 @@ i830MarkSync(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
+ switch (pI830->accel) {
#ifdef I830_USE_XAA
- if (!pI830->useEXA && pI830->AccelInfoRec)
- pI830->AccelInfoRec->NeedToSync = TRUE;
+ case ACCEL_XAA:
+ if (pI830->AccelInfoRec)
+ pI830->AccelInfoRec->NeedToSync = TRUE;
+ break;
#endif
#ifdef I830_USE_EXA
- if (pI830->useEXA && pI830->EXADriverPtr) {
- ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
- exaMarkSync(pScreen);
- }
+ case ACCEL_EXA:
+ if (pI830->EXADriverPtr) {
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ exaMarkSync(pScreen);
+ }
+ break;
+#endif
+#ifdef I830_USE_UXA
+ case ACCEL_UXA:
+ if (pI830->uxa_driver) {
+ ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+ exaMarkSync(pScreen);
+ }
+ break;
#endif
+ default:
+ break;
+ }
}
void
diff --git a/src/i830_exa.c b/src/i830_exa.c
index 75ccd742..a6705f48 100644
--- a/src/i830_exa.c
+++ b/src/i830_exa.c
@@ -430,7 +430,7 @@ I830EXAInit(ScreenPtr pScreen)
pI830->EXADriverPtr = exaDriverAlloc();
if (pI830->EXADriverPtr == NULL) {
- pI830->noAccel = TRUE;
+ pI830->accel = ACCEL_NONE;
return FALSE;
}
memset(pI830->EXADriverPtr, 0, sizeof(*pI830->EXADriverPtr));
@@ -558,7 +558,7 @@ I830EXAInit(ScreenPtr pScreen)
pI830->EXADriverPtr->exa_minor = 0;
if(!exaDriverInit(pScreen, pI830->EXADriverPtr)) {
xfree(pI830->EXADriverPtr);
- pI830->noAccel = TRUE;
+ pI830->accel = ACCEL_NONE;
return FALSE;
}
}
@@ -568,6 +568,133 @@ I830EXAInit(ScreenPtr pScreen)
return TRUE;
}
+static Bool
+i830_uxa_pixmap_is_offscreen(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ /* XXX for now, eventually we'll support 'real' off-screen pixmaps */
+ if ((void *)pPixmap->devPrivate.ptr >= (void *)pI830->FbBase &&
+ (void *)pPixmap->devPrivate.ptr <
+ (void *)(pI830->FbBase + pI830->FbMapSize))
+ {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+Bool
+i830_uxa_init (ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ pI830->uxa_driver = uxa_driver_alloc();
+ if (pI830->uxa_driver == NULL) {
+ pI830->accel = ACCEL_NONE;
+ return FALSE;
+ }
+ memset(pI830->uxa_driver, 0, sizeof(*pI830->uxa_driver));
+
+ pI830->bufferOffset = 0;
+ pI830->uxa_driver->uxa_major = 1;
+ pI830->uxa_driver->uxa_minor = 0;
+
+ /* Limits are described in the BLT engine chapter under Graphics Data Size
+ * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
+ * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
+ *
+ * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
+ *
+ * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
+ * i965 limits 3D surface to 4kB-aligned offset if tiled.
+ * i965 limits 3D surfaces to w,h of ?,8192.
+ * i965 limits 3D surface to pitch of 1B - 128kB.
+ * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
+ * i965 limits 3D surface pitch alignment to 512B if tiled.
+ * i965 limits 3D destination drawing rect to w,h of 8192,8192.
+ *
+ * i915 limits 3D textures to 4B-aligned offset if un-tiled.
+ * i915 limits 3D textures to ~4kB-aligned offset if tiled.
+ * i915 limits 3D textures to width,height of 2048,2048.
+ * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
+ * i915 limits 3D destination to ~4kB-aligned offset if tiled.
+ * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
+ * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
+ * i915 limits 3D destination to POT aligned pitch if tiled.
+ * i915 limits 3D destination drawing rect to w,h of 2048,2048.
+ *
+ * i845 limits 3D textures to 4B-aligned offset if un-tiled.
+ * i845 limits 3D textures to ~4kB-aligned offset if tiled.
+ * i845 limits 3D textures to width,height of 2048,2048.
+ * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
+ * i845 limits 3D destination to 4B-aligned offset if un-tiled.
+ * i845 limits 3D destination to ~4kB-aligned offset if tiled.
+ * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
+ * i845 limits 3D destination drawing rect to w,h of 2048,2048.
+ *
+ * For the tiled issues, the only tiled buffer we draw to should be
+ * the front, which will have an appropriate pitch/offset already set up,
+ * so EXA doesn't need to worry.
+ */
+ if (IS_I965G(pI830)) {
+ pI830->uxa_driver->maxX = 8192;
+ pI830->uxa_driver->maxY = 8192;
+ } else {
+ pI830->uxa_driver->maxX = 2048;
+ pI830->uxa_driver->maxY = 2048;
+ }
+
+ /* Sync */
+ pI830->uxa_driver->WaitMarker = I830EXASync;
+
+ /* Solid fill */
+ pI830->uxa_driver->PrepareSolid = I830EXAPrepareSolid;
+ pI830->uxa_driver->Solid = I830EXASolid;
+ pI830->uxa_driver->DoneSolid = I830EXADoneSolid;
+
+ /* Copy */
+ pI830->uxa_driver->PrepareCopy = I830EXAPrepareCopy;
+ pI830->uxa_driver->Copy = I830EXACopy;
+ pI830->uxa_driver->DoneCopy = I830EXADoneCopy;
+
+ /* Composite */
+ if (!IS_I9XX(pI830)) {
+ pI830->uxa_driver->CheckComposite = i830_check_composite;
+ pI830->uxa_driver->PrepareComposite = i830_prepare_composite;
+ pI830->uxa_driver->Composite = i830_composite;
+ pI830->uxa_driver->DoneComposite = i830_done_composite;
+ } else if (IS_I915G(pI830) || IS_I915GM(pI830) ||
+ IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830))
+ {
+ pI830->uxa_driver->CheckComposite = i915_check_composite;
+ pI830->uxa_driver->PrepareComposite = i915_prepare_composite;
+ pI830->uxa_driver->Composite = i830_composite;
+ pI830->uxa_driver->DoneComposite = i830_done_composite;
+ } else {
+ pI830->uxa_driver->CheckComposite = i965_check_composite;
+ pI830->uxa_driver->PrepareComposite = i965_prepare_composite;
+ pI830->uxa_driver->Composite = i965_composite;
+ pI830->uxa_driver->DoneComposite = i830_done_composite;
+ }
+ pI830->uxa_driver->PixmapIsOffscreen = i830_uxa_pixmap_is_offscreen;
+
+ if(!uxa_driver_init(pScreen, pI830->uxa_driver)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "UXA initialization failed\n");
+ xfree(pI830->uxa_driver);
+ pI830->accel = ACCEL_NONE;
+ return FALSE;
+ }
+
+ I830SelectBuffer(pScrn, I830_SELECT_FRONT);
+
+ return TRUE;
+}
+
#ifdef XF86DRI
#ifndef ExaOffscreenMarkUsed
diff --git a/src/i830_memory.c b/src/i830_memory.c
index b62bda05..c1748b3e 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -449,7 +449,7 @@ i830_allocator_init(ScrnInfoPtr pScrn, unsigned long offset, unsigned long size)
mmsize = size;
/* EXA area is fixed. */
- if (pI830->useEXA) {
+ if (pI830->accel == ACCEL_EXA) {
mmsize -= ROUND_TO_PAGE(3 * pScrn->displayWidth * pI830->cpp *
pScrn->virtualY);
}
@@ -1022,7 +1022,7 @@ i830_allocate_ringbuffer(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
- if (pI830->noAccel || pI830->memory_manager || pI830->LpRing->mem != NULL)
+ if (pI830->accel == ACCEL_NONE || pI830->memory_manager || pI830->LpRing->mem != NULL)
return TRUE;
/* We don't have any mechanism in the DRM yet to alert it that we've moved
@@ -1167,7 +1167,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
minspace = pitch * pScrn->virtualY;
avail = pScrn->videoRam * 1024;
- if (!pI830->useEXA) {
+ if (pI830->accel == ACCEL_XAA) {
maxCacheLines = (avail - minspace) / pitch;
/* This shouldn't happen. */
if (maxCacheLines < 0) {
@@ -1198,7 +1198,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
"Allocating %d scanlines for pixmap cache\n",
cacheLines);
} else {
- /* For EXA, we have a separate allocation for the linear allocator
+ /* For non-XAA, we have a separate allocation for the linear allocator
* which also does the pixmap cache.
*/
cacheLines = 0;
@@ -1213,7 +1213,7 @@ i830_allocate_framebuffer(ScrnInfoPtr pScrn, I830Ptr pI830, BoxPtr FbMemBox,
* acceleration operations (non-XY COLOR_BLT) can't be done to tiled
* buffers.
*/
- if (!pI830->useEXA && IS_I965G(pI830))
+ if (pI830->accel <= ACCEL_XAA && IS_I965G(pI830))
tiling = FALSE;
else
tiling = pI830->tiling;
@@ -1412,7 +1412,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn)
}
/* even in XAA, 965G needs state mem buffer for rendering */
- if (IS_I965G(pI830) && !pI830->noAccel &&
+ if (IS_I965G(pI830) && pI830->accel != ACCEL_NONE &&
pI830->gen4_render_state_mem == NULL)
{
pI830->gen4_render_state_mem =
@@ -1450,7 +1450,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn)
return FALSE;
#ifdef I830_USE_EXA
- if (pI830->useEXA) {
+ if (pI830->accel == ACCEL_EXA) {
if (pI830->exa_offscreen == NULL) {
/* Default EXA to having 3 screens worth of offscreen memory space
* (for pixmaps).
@@ -1478,7 +1478,7 @@ i830_allocate_2d_memory(ScrnInfoPtr pScrn)
}
#endif /* I830_USE_EXA */
- if (!pI830->noAccel && !pI830->useEXA) {
+ if (pI830->accel == ACCEL_XAA) {
/* The lifetime fixed offset of xaa scratch is probably not required,
* but we do some setup using it at XAAInit() time. And XAA may not
* end up being supported with GEM anyway.
diff --git a/src/i830_video.c b/src/i830_video.c
index 486f6708..1719835c 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -2460,13 +2460,13 @@ I830PutImage(ScrnInfoPtr pScrn,
}
#ifdef I830_USE_EXA
- if (pPriv->textured && pI830->useEXA) {
+ if (pPriv->textured && pI830->accel == ACCEL_EXA) {
/* Force the pixmap into framebuffer so we can draw to it. */
exaMoveInPixmap(pPixmap);
}
#endif
- if (pPriv->textured && !pI830->useEXA &&
+ if (pPriv->textured && pI830->accel <= ACCEL_XAA &&
(((char *)pPixmap->devPrivate.ptr < (char *)pI830->FbBase) ||
((char *)pPixmap->devPrivate.ptr >= (char *)pI830->FbBase +
pI830->FbMapSize))) {
diff --git a/uxa/Makefile.am b/uxa/Makefile.am
new file mode 100644
index 00000000..641b4146
--- /dev/null
+++ b/uxa/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES = libuxa.la
+
+# Override these since UXA doesn't need them and the needed files aren't
+# built (in hw/xfree86/os-support/solaris) until after UXA is built
+SOLARIS_ASM_CFLAGS=""
+
+INCLUDES = \
+ $(XORG_INCS)
+
+AM_CFLAGS = $(WARN_CFLAGS) $(XORG_CFLAGS) $(DIX_CFLAGS)
+
+libuxa_la_SOURCES = \
+ uxa.c \
+ uxa.h \
+ uxa-accel.c \
+ uxa-glyphs.c \
+ uxa-render.c \
+ uxa-priv.h \
+ uxa-unaccel.c
+
diff --git a/uxa/uxa-accel.c b/uxa/uxa-accel.c
new file mode 100644
index 00000000..7c7b3e9b
--- /dev/null
+++ b/uxa/uxa-accel.c
@@ -0,0 +1,1038 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Michel Dänzer <michel@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "uxa.h"
+
+static void
+uxa_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int n,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ BoxPtr pextent, pbox;
+ int nbox;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1;
+ int partX1, partX2;
+ int off_x, off_y;
+
+ if (uxa_screen->swappedOut || pGC->fillStyle != FillSolid ||
+ !(pPixmap = uxa_get_offscreen_pixmap (pDrawable, &off_x, &off_y)) ||
+ !(*uxa_screen->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+ uxa_check_fill_spans (pDrawable, pGC, n, ppt, pwidth, fSorted);
+ return;
+ }
+
+ pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (n--)
+ {
+ fullX1 = ppt->x;
+ fullY1 = ppt->y;
+ fullX2 = fullX1 + (int) *pwidth;
+ ppt++;
+ pwidth++;
+
+ if (fullY1 < extentY1 || extentY2 <= fullY1)
+ continue;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullX1 >= fullX2)
+ continue;
+
+ nbox = REGION_NUM_RECTS (pClip);
+ if (nbox == 1)
+ {
+ (*uxa_screen->info->Solid) (pPixmap,
+ fullX1 + off_x, fullY1 + off_y,
+ fullX2 + off_x, fullY1 + 1 + off_y);
+ }
+ else
+ {
+ pbox = REGION_RECTS(pClip);
+ while(nbox--)
+ {
+ if (pbox->y1 <= fullY1 && fullY1 < pbox->y2)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+ if (partX2 > partX1) {
+ (*uxa_screen->info->Solid) (pPixmap,
+ partX1 + off_x, fullY1 + off_y,
+ partX2 + off_x, fullY1 + 1 + off_y);
+ }
+ }
+ pbox++;
+ }
+ }
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pScreen);
+}
+
+static Bool
+uxa_do_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int format, char *bits, int src_stride)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable);
+ RegionPtr pClip;
+ BoxPtr pbox;
+ int nbox;
+ int xoff, yoff;
+ int bpp = pDrawable->bitsPerPixel;
+ Bool access_prepared = FALSE;
+
+ /* Don't bother with under 8bpp, XYPixmaps. */
+ if (format != ZPixmap || bpp < 8)
+ return FALSE;
+
+ /* Only accelerate copies: no rop or planemask. */
+ if (!UXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
+ return FALSE;
+
+ if (uxa_screen->swappedOut)
+ return FALSE;
+
+ pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPix || !uxa_screen->info->UploadToScreen)
+ return FALSE;
+
+ x += pDrawable->x;
+ y += pDrawable->y;
+
+ pClip = fbGetCompositeClip(pGC);
+ for (nbox = REGION_NUM_RECTS(pClip),
+ pbox = REGION_RECTS(pClip);
+ nbox--;
+ pbox++)
+ {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w;
+ int y2 = y + h;
+ char *src;
+ Bool ok;
+
+ if (x1 < pbox->x1)
+ x1 = pbox->x1;
+ if (y1 < pbox->y1)
+ y1 = pbox->y1;
+ if (x2 > pbox->x2)
+ x2 = pbox->x2;
+ if (y2 > pbox->y2)
+ y2 = pbox->y2;
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
+ ok = uxa_screen->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
+ x2 - x1, y2 - y1, src, src_stride);
+ /* If we fail to accelerate the upload, fall back to using unaccelerated
+ * fb calls.
+ */
+ if (!ok) {
+ FbStip *dst;
+ FbStride dst_stride;
+ int dstBpp;
+ int dstXoff, dstYoff;
+
+ if (!access_prepared) {
+ uxa_prepare_access(pDrawable, UXA_PREPARE_DEST);
+
+ access_prepared = TRUE;
+ }
+
+ fbGetStipDrawable(pDrawable, dst, dst_stride, dstBpp,
+ dstXoff, dstYoff);
+
+ fbBltStip((FbStip *)bits + (y1 - y) * (src_stride / sizeof(FbStip)),
+ src_stride / sizeof(FbStip),
+ (x1 - x) * dstBpp,
+ dst + (y1 + dstYoff) * dst_stride,
+ dst_stride,
+ (x1 + dstXoff) * dstBpp,
+ (x2 - x1) * dstBpp,
+ y2 - y1,
+ GXcopy, FB_ALLONES, dstBpp);
+ }
+ }
+
+ if (access_prepared)
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+ else
+ uxa_mark_sync(pDrawable->pScreen);
+
+ return TRUE;
+}
+
+#ifdef MITSHM
+
+static Bool
+uxa_do_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
+ unsigned int format, int w, int h, int sx, int sy, int sw,
+ int sh, int dx, int dy, char *data)
+{
+ int src_stride = PixmapBytePad(w, depth);
+
+ if (uxa_do_put_image(pDrawable, pGC, depth, dx, dy, sw, sh, format, data +
+ sy * src_stride + sx * BitsPerPixel(depth) / 8,
+ src_stride))
+ return TRUE;
+
+ if (format == ZPixmap)
+ {
+ PixmapPtr pPixmap;
+
+ pPixmap = GetScratchPixmapHeader(pDrawable->pScreen, w, h, depth,
+ BitsPerPixel(depth), PixmapBytePad(w, depth), (pointer)data);
+ if (!pPixmap)
+ return FALSE;
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+
+ fbCopyArea((DrawablePtr)pPixmap, pDrawable, pGC, sx, sy, sw, sh, dx, dy);
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+
+ FreeScratchPixmapHeader(pPixmap);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* The actual ShmPutImage isn't wrapped by the damage layer, so we need to
+ * inform any interested parties of the damage incurred to the drawable.
+ *
+ * We also need to set the pending damage to ensure correct migration in all
+ * cases.
+ */
+void
+uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
+ int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
+ char *data)
+{
+ if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh,
+ dx, dy, data)) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbShmPutImage(pDrawable, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
+ data);
+ uxa_finish_access(pDrawable, UXA_PREPARE_DEST);
+ }
+}
+
+ShmFuncs uxa_shm_funcs = { NULL, uxa_shm_put_image };
+
+#endif
+
+static void
+uxa_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
+ int w, int h, int leftPad, int format, char *bits)
+{
+#ifdef MITSHM
+ if (!uxa_do_shm_put_image(pDrawable, pGC, depth, format, w, h, 0, 0, w, h, x, y,
+ bits))
+#else
+ if (!uxa_do_put_image(pDrawable, pGC, depth, x, y, w, h, format, bits,
+ PixmapBytePad(w, pDrawable->depth)))
+#endif
+ uxa_check_put_image(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+ bits);
+}
+
+static Bool inline
+uxa_copy_n_to_n_two_dir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+ GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ int dirsetup;
+
+ /* Need to get both pixmaps to call the driver routines */
+ pSrcPixmap = uxa_get_offscreen_pixmap (pSrcDrawable, &src_off_x, &src_off_y);
+ pDstPixmap = uxa_get_offscreen_pixmap (pDstDrawable, &dst_off_x, &dst_off_y);
+ if (!pSrcPixmap || !pDstPixmap)
+ return FALSE;
+
+ /*
+ * Now the case of a chip that only supports xdir = ydir = 1 or
+ * xdir = ydir = -1, but we have xdir != ydir.
+ */
+ dirsetup = 0; /* No direction set up yet. */
+ for (; nbox; pbox++, nbox--) {
+ if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = -1 blit instead. */
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx < 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = 1 blit instead. */
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ } else if (dx >= 0) {
+ /*
+ * xdir = 1, ydir = -1.
+ * Perform line-by-line xdir = ydir = 1 blits, going up.
+ */
+ int i;
+ if (dirsetup != 1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = 1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ } else {
+ /*
+ * xdir = -1, ydir = 1.
+ * Perform line-by-line xdir = ydir = -1 blits, going down.
+ */
+ int i;
+ if (dirsetup != -1) {
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ dirsetup = -1;
+ if (!(*uxa_screen->info->PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = 0; i < pbox->y2 - pbox->y1; i++)
+ (*uxa_screen->info->Copy)(pDstPixmap,
+ src_off_x + pbox->x1 + dx,
+ src_off_y + pbox->y1 + dy + i,
+ dst_off_x + pbox->x1,
+ dst_off_y + pbox->y1 + i,
+ pbox->x2 - pbox->x1, 1);
+ }
+ }
+ if (dirsetup != 0)
+ uxa_screen->info->DoneCopy(pDstPixmap);
+ uxa_mark_sync(pDstDrawable->pScreen);
+ return TRUE;
+}
+
+void
+uxa_copy_n_to_n (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+ int src_off_x, src_off_y;
+ int dst_off_x, dst_off_y;
+ PixmapPtr pSrcPixmap, pDstPixmap;
+
+ pSrcPixmap = uxa_get_drawable_pixmap (pSrcDrawable);
+ pDstPixmap = uxa_get_drawable_pixmap (pDstDrawable);
+
+ uxa_get_drawable_deltas (pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
+ uxa_get_drawable_deltas (pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);
+
+ /* Mixed directions must be handled specially if the card is lame */
+ if ((uxa_screen->info->flags & UXA_TWO_BITBLT_DIRECTIONS) &&
+ reverse != upsidedown) {
+ if (uxa_copy_n_to_n_two_dir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ dx, dy))
+ return;
+ goto fallback;
+ }
+
+ if (!uxa_pixmap_is_offscreen(pSrcPixmap) ||
+ !uxa_pixmap_is_offscreen(pDstPixmap) ||
+ !(*uxa_screen->info->PrepareCopy) (pSrcPixmap, pDstPixmap, reverse ? -1 : 1,
+ upsidedown ? -1 : 1,
+ pGC ? pGC->alu : GXcopy,
+ pGC ? pGC->planemask : FB_ALLONES)) {
+ goto fallback;
+ }
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Copy) (pDstPixmap,
+ pbox->x1 + dx + src_off_x,
+ pbox->y1 + dy + src_off_y,
+ pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+ pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ (*uxa_screen->info->DoneCopy) (pDstPixmap);
+ uxa_mark_sync (pDstDrawable->pScreen);
+
+ return;
+
+fallback:
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrcDrawable, pDstDrawable,
+ uxa_drawable_location(pSrcDrawable),
+ uxa_drawable_location(pDstDrawable)));
+ uxa_prepare_access (pDstDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrcDrawable, UXA_PREPARE_SRC);
+ fbCopyNtoN (pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy, reverse,
+ upsidedown, bitplane, closure);
+ uxa_finish_access (pSrcDrawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDstDrawable, UXA_PREPARE_DEST);
+}
+
+RegionPtr
+uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDstDrawable->pScreen);
+
+ if (uxa_screen->swappedOut) {
+ return uxa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height, dstx, dsty);
+ }
+
+ return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
+ srcx, srcy, width, height,
+ dstx, dsty, uxa_copy_n_to_n, 0, NULL);
+}
+
+static void
+uxa_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ int i;
+ xRectangle *prect;
+
+ /* If we can't reuse the current GC as is, don't bother accelerating the
+ * points.
+ */
+ if (pGC->fillStyle != FillSolid) {
+ uxa_check_poly_point(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = xalloc(sizeof(xRectangle) * npt);
+ for (i = 0; i < npt; i++) {
+ prect[i].x = ppt[i].x;
+ prect[i].y = ppt[i].y;
+ if (i > 0 && mode == CoordModePrevious) {
+ prect[i].x += prect[i - 1].x;
+ prect[i].y += prect[i - 1].y;
+ }
+ prect[i].width = 1;
+ prect[i].height = 1;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt, prect);
+ xfree(prect);
+}
+
+/**
+ * uxa_poly_lines() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+uxa_poly_lines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr ppt)
+{
+ xRectangle *prect;
+ int x1, x2, y1, y2;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ pGC->fillStyle != FillSolid) {
+ uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ prect = xalloc(sizeof(xRectangle) * (npt - 1));
+ x1 = ppt[0].x;
+ y1 = ppt[0].y;
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < npt - 1; i++) {
+ if (mode == CoordModePrevious) {
+ x2 = x1 + ppt[i + 1].x;
+ y2 = y1 + ppt[i + 1].y;
+ } else {
+ x2 = ppt[i + 1].x;
+ y2 = ppt[i + 1].y;
+ }
+
+ if (x1 != x2 && y1 != y2) {
+ xfree(prect);
+ uxa_check_poly_lines(pDrawable, pGC, mode, npt, ppt);
+ return;
+ }
+
+ if (x1 < x2) {
+ prect[i].x = x1;
+ prect[i].width = x2 - x1 + 1;
+ } else {
+ prect[i].x = x2;
+ prect[i].width = x1 - x2 + 1;
+ }
+ if (y1 < y2) {
+ prect[i].y = y1;
+ prect[i].height = y2 - y1 + 1;
+ } else {
+ prect[i].y = y2;
+ prect[i].height = y1 - y2 + 1;
+ }
+
+ x1 = x2;
+ y1 = y2;
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, npt - 1, prect);
+ xfree(prect);
+}
+
+/**
+ * uxa_poly_segment() checks if it can accelerate the lines as a group of
+ * horizontal or vertical lines (rectangles), and uses existing rectangle fill
+ * acceleration if so.
+ */
+static void
+uxa_poly_segment (DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg)
+{
+ xRectangle *prect;
+ int i;
+
+ /* Don't try to do wide lines or non-solid fill style. */
+ if (pGC->lineWidth != 0 || pGC->lineStyle != LineSolid ||
+ pGC->fillStyle != FillSolid)
+ {
+ uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+
+ /* If we have any non-horizontal/vertical, fall back. */
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 != pSeg[i].x2 && pSeg[i].y1 != pSeg[i].y2) {
+ uxa_check_poly_segment(pDrawable, pGC, nseg, pSeg);
+ return;
+ }
+ }
+
+ prect = xalloc(sizeof(xRectangle) * nseg);
+ for (i = 0; i < nseg; i++) {
+ if (pSeg[i].x1 < pSeg[i].x2) {
+ prect[i].x = pSeg[i].x1;
+ prect[i].width = pSeg[i].x2 - pSeg[i].x1 + 1;
+ } else {
+ prect[i].x = pSeg[i].x2;
+ prect[i].width = pSeg[i].x1 - pSeg[i].x2 + 1;
+ }
+ if (pSeg[i].y1 < pSeg[i].y2) {
+ prect[i].y = pSeg[i].y1;
+ prect[i].height = pSeg[i].y2 - pSeg[i].y1 + 1;
+ } else {
+ prect[i].y = pSeg[i].y2;
+ prect[i].height = pSeg[i].y1 - pSeg[i].y2 + 1;
+ }
+
+ /* don't paint last pixel */
+ if (pGC->capStyle == CapNotLast) {
+ if (prect[i].width == 1)
+ prect[i].height--;
+ else
+ prect[i].width--;
+ }
+ }
+ pGC->ops->PolyFillRect(pDrawable, pGC, nseg, prect);
+ xfree(prect);
+}
+
+static Bool uxa_fill_region_solid (DrawablePtr pDrawable, RegionPtr pRegion,
+ Pixel pixel, CARD32 planemask, CARD32 alu);
+
+static void
+uxa_poly_fill_rect(DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nrect,
+ xRectangle *prect)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ RegionPtr pClip = fbGetCompositeClip(pGC);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable);
+ register BoxPtr pbox;
+ BoxPtr pextent;
+ int extentX1, extentX2, extentY1, extentY2;
+ int fullX1, fullX2, fullY1, fullY2;
+ int partX1, partX2, partY1, partY2;
+ int xoff, yoff;
+ int xorg, yorg;
+ int n;
+ RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);
+
+ /* Compute intersection of rects and clip region */
+ REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
+ REGION_INTERSECT(pScreen, pReg, pClip, pReg);
+
+ if (!REGION_NUM_RECTS(pReg))
+ goto out;
+
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+
+ if (uxa_screen->swappedOut)
+ goto fallback;
+
+ /* For ROPs where overlaps don't matter, convert rectangles to region and
+ * call uxa_fill_region_{solid,tiled}.
+ */
+ if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
+ (nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
+ pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
+ pGC->alu == GXset)) {
+ if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
+ uxa_fill_region_solid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
+ pGC->fgPixel : pGC->tile.pixel, pGC->planemask,
+ pGC->alu)) ||
+ (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
+ uxa_fill_region_tiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
+ pGC->planemask, pGC->alu))) {
+ goto out;
+ }
+ }
+
+ if (pGC->fillStyle != FillSolid &&
+ !(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
+ {
+ goto fallback;
+ }
+
+ if (!uxa_pixmap_is_offscreen (pPixmap) ||
+ !(*uxa_screen->info->PrepareSolid) (pPixmap,
+ pGC->alu,
+ pGC->planemask,
+ pGC->fgPixel))
+ {
+fallback:
+ uxa_check_poly_fill_rect (pDrawable, pGC, nrect, prect);
+ goto out;
+ }
+
+ xorg = pDrawable->x;
+ yorg = pDrawable->y;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, pClip);
+ extentX1 = pextent->x1;
+ extentY1 = pextent->y1;
+ extentX2 = pextent->x2;
+ extentY2 = pextent->y2;
+ while (nrect--)
+ {
+ fullX1 = prect->x + xorg;
+ fullY1 = prect->y + yorg;
+ fullX2 = fullX1 + (int) prect->width;
+ fullY2 = fullY1 + (int) prect->height;
+ prect++;
+
+ if (fullX1 < extentX1)
+ fullX1 = extentX1;
+
+ if (fullY1 < extentY1)
+ fullY1 = extentY1;
+
+ if (fullX2 > extentX2)
+ fullX2 = extentX2;
+
+ if (fullY2 > extentY2)
+ fullY2 = extentY2;
+
+ if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
+ continue;
+ n = REGION_NUM_RECTS (pClip);
+ if (n == 1)
+ {
+ (*uxa_screen->info->Solid) (pPixmap,
+ fullX1 + xoff, fullY1 + yoff,
+ fullX2 + xoff, fullY2 + yoff);
+ }
+ else
+ {
+ pbox = REGION_RECTS(pClip);
+ /*
+ * clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect(),
+ * but rectangles may overlap each other here.
+ */
+ while(n--)
+ {
+ partX1 = pbox->x1;
+ if (partX1 < fullX1)
+ partX1 = fullX1;
+ partY1 = pbox->y1;
+ if (partY1 < fullY1)
+ partY1 = fullY1;
+ partX2 = pbox->x2;
+ if (partX2 > fullX2)
+ partX2 = fullX2;
+ partY2 = pbox->y2;
+ if (partY2 > fullY2)
+ partY2 = fullY2;
+
+ pbox++;
+
+ if (partX1 < partX2 && partY1 < partY2) {
+ (*uxa_screen->info->Solid) (pPixmap,
+ partX1 + xoff, partY1 + yoff,
+ partX2 + xoff, partY2 + yoff);
+ }
+ }
+ }
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+out:
+ REGION_UNINIT(pScreen, pReg);
+ REGION_DESTROY(pScreen, pReg);
+}
+
+const GCOps uxa_ops = {
+ uxa_fill_spans,
+ uxa_check_set_spans,
+ uxa_put_image,
+ uxa_copy_area,
+ uxa_check_copy_plane,
+ uxa_poly_point,
+ uxa_poly_lines,
+ uxa_poly_segment,
+ miPolyRectangle,
+ uxa_check_poly_arc,
+ miFillPolygon,
+ uxa_poly_fill_rect,
+ miPolyFillArc,
+ miPolyText8,
+ miPolyText16,
+ miImageText8,
+ miImageText16,
+ uxa_check_image_glyph_blt,
+ uxa_check_poly_glyph_blt,
+ uxa_check_push_pixels,
+};
+
+void
+uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ RegionRec rgnDst;
+ int dx, dy;
+ PixmapPtr pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin);
+
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
+#ifdef COMPOSITE
+ if (pPixmap->screen_x || pPixmap->screen_y)
+ REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+#endif
+
+ fbCopyRegion (&pPixmap->drawable, &pPixmap->drawable,
+ NULL,
+ &rgnDst, dx, dy, uxa_copy_n_to_n, 0, NULL);
+
+ REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
+}
+
+static Bool
+uxa_fill_region_solid (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ Pixel pixel,
+ CARD32 planemask,
+ CARD32 alu)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ int xoff, yoff;
+ Bool ret = FALSE;
+
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+ if (uxa_pixmap_is_offscreen (pPixmap) &&
+ (*uxa_screen->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
+ {
+ int nbox;
+ BoxPtr pBox;
+
+ nbox = REGION_NUM_RECTS (pRegion);
+ pBox = REGION_RECTS (pRegion);
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
+ pBox->y2);
+ pBox++;
+ }
+ (*uxa_screen->info->DoneSolid) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+ ret = TRUE;
+ }
+
+ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+
+ return ret;
+}
+
+/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
+ * Based on fbFillRegionTiled(), fbTile().
+ */
+Bool
+uxa_fill_region_tiled (DrawablePtr pDrawable,
+ RegionPtr pRegion,
+ PixmapPtr pTile,
+ DDXPointPtr pPatOrg,
+ CARD32 planemask,
+ CARD32 alu)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ PixmapPtr pPixmap;
+ int xoff, yoff;
+ int tileWidth, tileHeight;
+ int nbox = REGION_NUM_RECTS (pRegion);
+ BoxPtr pBox = REGION_RECTS (pRegion);
+ Bool ret = FALSE;
+
+ tileWidth = pTile->drawable.width;
+ tileHeight = pTile->drawable.height;
+
+ /* If we're filling with a solid color, grab it out and go to
+ * FillRegionSolid, saving numerous copies.
+ */
+ if (tileWidth == 1 && tileHeight == 1)
+ return uxa_fill_region_solid(pDrawable, pRegion,
+ uxa_get_pixmap_first_pixel (pTile), planemask,
+ alu);
+
+ pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ uxa_get_drawable_deltas(pDrawable, pPixmap, &xoff, &yoff);
+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
+
+ pPixmap = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (!pPixmap || !uxa_pixmap_is_offscreen(pTile))
+ goto out;
+
+ if ((*uxa_screen->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
+ {
+ while (nbox--)
+ {
+ int height = pBox->y2 - pBox->y1;
+ int dstY = pBox->y1;
+ int tileY;
+
+ modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
+
+ while (height > 0) {
+ int width = pBox->x2 - pBox->x1;
+ int dstX = pBox->x1;
+ int tileX;
+ int h = tileHeight - tileY;
+
+ if (h > height)
+ h = height;
+ height -= h;
+
+ modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
+ tileX);
+
+ while (width > 0) {
+ int w = tileWidth - tileX;
+ if (w > width)
+ w = width;
+ width -= w;
+
+ (*uxa_screen->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
+ w, h);
+ dstX += w;
+ tileX = 0;
+ }
+ dstY += h;
+ tileY = 0;
+ }
+ pBox++;
+ }
+ (*uxa_screen->info->DoneCopy) (pPixmap);
+ uxa_mark_sync(pDrawable->pScreen);
+
+ ret = TRUE;
+ }
+
+out:
+ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
+
+ return ret;
+}
+
+
+/**
+ * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
+ *
+ * This is probably the only case we actually care about. The rest fall through
+ * to migration and fbGetImage, which hopefully will result in migration pushing
+ * the pixmap out of framebuffer.
+ */
+void
+uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDrawable->pScreen);
+ BoxRec Box;
+ PixmapPtr pPix = uxa_get_drawable_pixmap (pDrawable);
+ int xoff, yoff;
+ Bool ok;
+
+ uxa_get_drawable_deltas (pDrawable, pPix, &xoff, &yoff);
+
+ Box.x1 = pDrawable->y + x + xoff;
+ Box.y1 = pDrawable->y + y + yoff;
+ Box.x2 = Box.x1 + w;
+ Box.y2 = Box.y1 + h;
+
+ if (uxa_screen->swappedOut)
+ goto fallback;
+
+ pPix = uxa_get_offscreen_pixmap (pDrawable, &xoff, &yoff);
+
+ if (pPix == NULL || uxa_screen->info->DownloadFromScreen == NULL)
+ goto fallback;
+
+ /* Only cover the ZPixmap, solid copy case. */
+ if (format != ZPixmap || !UXA_PM_IS_SOLID(pDrawable, planeMask))
+ goto fallback;
+
+ /* Only try to handle the 8bpp and up cases, since we don't want to think
+ * about <8bpp.
+ */
+ if (pDrawable->bitsPerPixel < 8)
+ goto fallback;
+
+ ok = uxa_screen->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
+ pDrawable->y + y + yoff, w, h, d,
+ PixmapBytePad(w, pDrawable->depth));
+ if (ok) {
+ uxa_wait_sync(pDrawable->pScreen);
+ goto out;
+ }
+
+fallback:
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_SRC);
+ fbGetImage (pDrawable, x, y, w, h, format, planeMask, d);
+ uxa_finish_access (pDrawable, UXA_PREPARE_SRC);
+
+out:
+ return;
+}
diff --git a/uxa/uxa-glyphs.c b/uxa/uxa-glyphs.c
new file mode 100644
index 00000000..3c446405
--- /dev/null
+++ b/uxa/uxa-glyphs.c
@@ -0,0 +1,880 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ * Partly based on code Copyright © 2000 SuSE, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. SuSE makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor <otaylor@fishsoup.net>
+ * Based on code by: Keith Packard
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+
+#include "mipict.h"
+
+#if DEBUG_GLYPH_CACHE
+#define DBG_GLYPH_CACHE(a) ErrorF a
+#else
+#define DBG_GLYPH_CACHE(a)
+#endif
+
+/* Width of the pixmaps we use for the caches; this should be less than
+ * max texture size of the driver; this may need to actually come from
+ * the driver.
+ */
+#define CACHE_PICTURE_WIDTH 1024
+
+/* Maximum number of glyphs we buffer on the stack before flushing
+ * rendering to the mask or destination surface.
+ */
+#define GLYPH_BUFFER_SIZE 256
+
+typedef struct {
+ PicturePtr source;
+ uxa_composite_rect_t rects[GLYPH_BUFFER_SIZE];
+ int count;
+} uxa_glyph_buffer_t;
+
+typedef enum {
+ UXA_GLYPH_SUCCESS, /* Glyph added to render buffer */
+ UXA_GLYPH_FAIL, /* out of memory, etc */
+ UXA_GLYPH_NEED_FLUSH, /* would evict a glyph already in the buffer */
+} uxa_glyph_cache_result_t;
+
+void
+uxa_glyphs_init(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i = 0;
+
+ memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
+
+ uxa_screen->glyphCaches[i].format = PICT_a8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 16;
+ i++;
+ uxa_screen->glyphCaches[i].format = PICT_a8r8g8b8;
+ uxa_screen->glyphCaches[i].glyphWidth = uxa_screen->glyphCaches[i].glyphHeight = 32;
+ i++;
+
+ assert(i == UXA_NUM_GLYPH_CACHES);
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_screen->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / uxa_screen->glyphCaches[i].glyphWidth;
+ uxa_screen->glyphCaches[i].size = 256;
+ uxa_screen->glyphCaches[i].hashSize = 557;
+ }
+}
+
+static void
+uxa_unrealize_glyph_caches(ScreenPtr pScreen,
+ unsigned int format)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (cache->format != format)
+ continue;
+
+ if (cache->picture) {
+ FreePicture ((pointer) cache->picture, (XID) 0);
+ cache->picture = NULL;
+ }
+
+ if (cache->hashEntries) {
+ xfree(cache->hashEntries);
+ cache->hashEntries = NULL;
+ }
+
+ if (cache->glyphs) {
+ xfree(cache->glyphs);
+ cache->glyphs = NULL;
+ }
+ cache->glyphCount = 0;
+ }
+}
+
+/* All caches for a single format share a single pixmap for glyph storage,
+ * allowing mixing glyphs of different sizes without paying a penalty
+ * for switching between source pixmaps. (Note that for a size of font
+ * right at the border between two sizes, we might be switching for almost
+ * every glyph.)
+ *
+ * This function allocates the storage pixmap, and then fills in the
+ * rest of the allocated structures for all caches with the given format.
+ */
+static Bool
+uxa_realize_glyph_caches(ScreenPtr pScreen,
+ unsigned int format)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int depth = PIXMAN_FORMAT_DEPTH(format);
+ PictFormatPtr pPictFormat;
+ PixmapPtr pPixmap;
+ PicturePtr pPicture;
+ int height;
+ int i;
+ int error;
+
+ pPictFormat = PictureMatchFormat(pScreen, depth, format);
+ if (!pPictFormat)
+ return FALSE;
+
+ /* Compute the total vertical size needed for the format */
+
+ height = 0;
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+ int rows;
+
+ if (cache->format != format)
+ continue;
+
+ cache->yOffset = height;
+
+ rows = (cache->size + cache->columns - 1) / cache->columns;
+ height += rows * cache->glyphHeight;
+ }
+
+ /* Now allocate the pixmap and picture */
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen,
+ CACHE_PICTURE_WIDTH,
+ height, depth, 0);
+ if (!pPixmap)
+ return FALSE;
+
+ pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
+ 0, 0, serverClient, &error);
+
+ (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
+
+ if (!pPicture)
+ return FALSE;
+
+ /* And store the picture in all the caches for the format */
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+ int j;
+
+ if (cache->format != format)
+ continue;
+
+ cache->picture = pPicture;
+ cache->picture->refcnt++;
+ cache->hashEntries = xalloc(sizeof(int) * cache->hashSize);
+ cache->glyphs = xalloc(sizeof(uxa_cached_glyph_t) * cache->size);
+ cache->glyphCount = 0;
+
+ if (!cache->hashEntries || !cache->glyphs)
+ goto bail;
+
+ for (j = 0; j < cache->hashSize; j++)
+ cache->hashEntries[j] = -1;
+
+ cache->evictionPosition = rand() % cache->size;
+ }
+
+ /* Each cache references the picture individually */
+ FreePicture ((pointer) pPicture, (XID) 0);
+ return TRUE;
+
+bail:
+ uxa_unrealize_glyph_caches(pScreen, format);
+ return FALSE;
+}
+
+void
+uxa_glyphs_fini (ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ int i;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (cache->picture)
+ uxa_unrealize_glyph_caches(pScreen, cache->format);
+ }
+}
+
+static int
+uxa_glyph_cache_hash_lookup(uxa_glyph_cache_t *cache, GlyphPtr pGlyph)
+{
+ int slot;
+
+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ int entryPos = cache->hashEntries[slot];
+ if (entryPos == -1)
+ return -1;
+
+ if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
+ return entryPos;
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+static void
+uxa_glyph_cache_hash_insert(uxa_glyph_cache_t *cache,
+ GlyphPtr pGlyph,
+ int pos)
+{
+ int slot;
+
+ memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
+
+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ if (cache->hashEntries[slot] == -1) {
+ cache->hashEntries[slot] = pos;
+ return;
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+static void
+uxa_glyph_cache_hash_remove(uxa_glyph_cache_t *cache,
+ int pos)
+{
+ int slot;
+ int emptiedSlot = -1;
+
+ slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
+
+ while (TRUE) { /* hash table can never be full */
+ int entryPos = cache->hashEntries[slot];
+
+ if (entryPos == -1)
+ return;
+
+ if (entryPos == pos) {
+ cache->hashEntries[slot] = -1;
+ emptiedSlot = slot;
+ } else if (emptiedSlot != -1) {
+ /* See if we can move this entry into the emptied slot, we can't
+ * do that if if entry would have hashed between the current position
+ * and the emptied slot. (taking wrapping into account). Bad positions
+ * are:
+ *
+ * | XXXXXXXXXX |
+ * i j
+ *
+ * |XXX XXXX|
+ * j i
+ *
+ * i - slot, j - emptiedSlot
+ *
+ * (Knuth 6.4R)
+ */
+
+ int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
+
+ if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
+ (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot))))
+ {
+ cache->hashEntries[emptiedSlot] = entryPos;
+ cache->hashEntries[slot] = -1;
+ emptiedSlot = slot;
+ }
+ }
+
+ slot--;
+ if (slot < 0)
+ slot = cache->hashSize - 1;
+ }
+}
+
+#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
+#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
+
+/* The most efficient thing to way to upload the glyph to the screen
+ * is to use the UploadToScreen() driver hook; this allows us to
+ * pipeline glyph uploads and to avoid creating offscreen pixmaps for
+ * glyphs that we'll never use again.
+ */
+static Bool
+uxa_glyph_cache_upload_glyph(ScreenPtr pScreen,
+ uxa_glyph_cache_t *cache,
+ int pos,
+ GlyphPtr pGlyph)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum];
+ PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable;
+ PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable;
+ int cacheXoff, cacheYoff;
+
+ if (!uxa_screen->info->UploadToScreen || uxa_screen->swappedOut)
+ return FALSE;
+
+ /* If the glyph pixmap is already uploaded, no point in doing
+ * things this way */
+ if (uxa_pixmap_is_offscreen(pGlyphPixmap))
+ return FALSE;
+
+ /* UploadToScreen only works if bpp match */
+ if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
+ return FALSE;
+
+ pCachePixmap = uxa_get_offscreen_pixmap ((DrawablePtr)pCachePixmap, &cacheXoff, &cacheYoff);
+ if (!pCachePixmap)
+ return FALSE;
+
+ if (!uxa_screen->info->UploadToScreen(pCachePixmap,
+ CACHE_X(pos) + cacheXoff,
+ CACHE_Y(pos) + cacheYoff,
+ pGlyph->info.width,
+ pGlyph->info.height,
+ (char *)pGlyphPixmap->devPrivate.ptr,
+ pGlyphPixmap->devKind))
+ return FALSE;
+
+ return TRUE;
+}
+
+static uxa_glyph_cache_result_t
+uxa_glyph_cache_buffer_glyph(ScreenPtr pScreen,
+ uxa_glyph_cache_t *cache,
+ uxa_glyph_buffer_t *buffer,
+ GlyphPtr pGlyph,
+ int xGlyph,
+ int yGlyph)
+{
+ uxa_composite_rect_t *rect;
+ int pos;
+
+ if (buffer->source && buffer->source != cache->picture)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ if (!cache->picture) {
+ if (!uxa_realize_glyph_caches(pScreen, cache->format))
+ return UXA_GLYPH_FAIL;
+ }
+
+ DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
+ cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB",
+ (long)*(CARD32 *) pGlyph->sha1));
+
+ pos = uxa_glyph_cache_hash_lookup(cache, pGlyph);
+ if (pos != -1) {
+ DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
+ } else {
+ if (cache->glyphCount < cache->size) {
+ /* Space remaining; we fill from the start */
+ pos = cache->glyphCount;
+ cache->glyphCount++;
+ DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
+
+ uxa_glyph_cache_hash_insert(cache, pGlyph, pos);
+
+ } else {
+ /* Need to evict an entry. We have to see if any glyphs
+ * already in the output buffer were at this position in
+ * the cache
+ */
+
+ pos = cache->evictionPosition;
+ DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
+ if (buffer->count) {
+ int x, y;
+ int i;
+
+ x = CACHE_X(pos);
+ y = CACHE_Y(pos);
+
+ for (i = 0; i < buffer->count; i++) {
+ if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
+ DBG_GLYPH_CACHE((" must flush buffer\n"));
+ return UXA_GLYPH_NEED_FLUSH;
+ }
+ }
+ }
+
+ /* OK, we're all set, swap in the new glyph */
+ uxa_glyph_cache_hash_remove(cache, pos);
+ uxa_glyph_cache_hash_insert(cache, pGlyph, pos);
+
+ /* And pick a new eviction position */
+ cache->evictionPosition = rand() % cache->size;
+ }
+
+ /* Now actually upload the glyph into the cache picture; if
+ * we can't do it with UploadToScreen (because the glyph is
+ * offscreen, etc), we fall back to CompositePicture.
+ */
+ if (!uxa_glyph_cache_upload_glyph(pScreen, cache, pos, pGlyph)) {
+ CompositePicture (PictOpSrc,
+ GlyphPicture(pGlyph)[pScreen->myNum],
+ None,
+ cache->picture,
+ 0, 0,
+ 0, 0,
+ CACHE_X(pos),
+ CACHE_Y(pos),
+ pGlyph->info.width,
+ pGlyph->info.height);
+ }
+
+ }
+
+
+ buffer->source = cache->picture;
+
+ rect = &buffer->rects[buffer->count];
+ rect->xSrc = CACHE_X(pos);
+ rect->ySrc = CACHE_Y(pos);
+ rect->xDst = xGlyph - pGlyph->info.x;
+ rect->yDst = yGlyph - pGlyph->info.y;
+ rect->width = pGlyph->info.width;
+ rect->height = pGlyph->info.height;
+
+ buffer->count++;
+
+ return UXA_GLYPH_SUCCESS;
+}
+
+#undef CACHE_X
+#undef CACHE_Y
+
+static uxa_glyph_cache_result_t
+uxa_buffer_glyph(ScreenPtr pScreen,
+ uxa_glyph_buffer_t *buffer,
+ GlyphPtr pGlyph,
+ int xGlyph,
+ int yGlyph)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
+ int width = pGlyph->info.width;
+ int height = pGlyph->info.height;
+ uxa_composite_rect_t *rect;
+ PicturePtr source;
+ int i;
+
+ if (buffer->count == GLYPH_BUFFER_SIZE)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ if (PICT_FORMAT_BPP(format) == 1)
+ format = PICT_a8;
+
+ for (i = 0; i < UXA_NUM_GLYPH_CACHES; i++) {
+ uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
+
+ if (format == cache->format &&
+ width <= cache->glyphWidth &&
+ height <= cache->glyphHeight) {
+ uxa_glyph_cache_result_t result = uxa_glyph_cache_buffer_glyph(pScreen, &uxa_screen->glyphCaches[i],
+ buffer,
+ pGlyph, xGlyph, yGlyph);
+ switch (result) {
+ case UXA_GLYPH_FAIL:
+ break;
+ case UXA_GLYPH_SUCCESS:
+ case UXA_GLYPH_NEED_FLUSH:
+ return result;
+ }
+ }
+ }
+
+ /* Couldn't find the glyph in the cache, use the glyph picture directly */
+
+ source = GlyphPicture(pGlyph)[pScreen->myNum];
+ if (buffer->source && buffer->source != source)
+ return UXA_GLYPH_NEED_FLUSH;
+
+ buffer->source = source;
+
+ rect = &buffer->rects[buffer->count];
+ rect->xSrc = 0;
+ rect->ySrc = 0;
+ rect->xDst = xGlyph - pGlyph->info.x;
+ rect->yDst = yGlyph - pGlyph->info.y;
+ rect->width = pGlyph->info.width;
+ rect->height = pGlyph->info.height;
+
+ buffer->count++;
+
+ return UXA_GLYPH_SUCCESS;
+}
+
+static void
+uxa_glyphs_to_mask(PicturePtr pMask,
+ uxa_glyph_buffer_t *buffer)
+{
+ uxa_composite_rects(PictOpAdd, buffer->source, pMask,
+ buffer->count, buffer->rects);
+
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+static void
+uxa_glyphs_to_dst(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ uxa_glyph_buffer_t *buffer,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xDst,
+ INT16 yDst)
+{
+ int i;
+
+ for (i = 0; i < buffer->count; i++) {
+ uxa_composite_rect_t *rect = &buffer->rects[i];
+
+ CompositePicture (op,
+ pSrc,
+ buffer->source,
+ pDst,
+ xSrc + rect->xDst - xDst,
+ ySrc + rect->yDst - yDst,
+ rect->xSrc,
+ rect->ySrc,
+ rect->xDst,
+ rect->yDst,
+ rect->width,
+ rect->height);
+ }
+
+ buffer->count = 0;
+ buffer->source = NULL;
+}
+
+/* Cut and paste from render/glyph.c - probably should export it instead */
+static void
+uxa_glyph_extents (int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs,
+ BoxPtr extents)
+{
+ int x1, x2, y1, y2;
+ int n;
+ GlyphPtr glyph;
+ int x, y;
+
+ x = 0;
+ y = 0;
+ extents->x1 = MAXSHORT;
+ extents->x2 = MINSHORT;
+ extents->y1 = MAXSHORT;
+ extents->y2 = MINSHORT;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--)
+ {
+ glyph = *glyphs++;
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ x2 = x1 + glyph->info.width;
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ y2 = y1 + glyph->info.height;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+ if (x1 < extents->x1)
+ extents->x1 = x1;
+ if (x2 > extents->x2)
+ extents->x2 = x2;
+ if (y1 < extents->y1)
+ extents->y1 = y1;
+ if (y2 > extents->y2)
+ extents->y2 = y2;
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+}
+
+/**
+ * Returns TRUE if the glyphs in the lists intersect. Only checks based on
+ * bounding box, which appears to be good enough to catch most cases at least.
+ */
+static Bool
+uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+ int x1, x2, y1, y2;
+ int n;
+ GlyphPtr glyph;
+ int x, y;
+ BoxRec extents;
+ Bool first = TRUE;
+
+ x = 0;
+ y = 0;
+ while (nlist--) {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ list++;
+ while (n--) {
+ glyph = *glyphs++;
+
+ if (glyph->info.width == 0 || glyph->info.height == 0) {
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ continue;
+ }
+
+ x1 = x - glyph->info.x;
+ if (x1 < MINSHORT)
+ x1 = MINSHORT;
+ y1 = y - glyph->info.y;
+ if (y1 < MINSHORT)
+ y1 = MINSHORT;
+ x2 = x1 + glyph->info.width;
+ if (x2 > MAXSHORT)
+ x2 = MAXSHORT;
+ y2 = y1 + glyph->info.height;
+ if (y2 > MAXSHORT)
+ y2 = MAXSHORT;
+
+ if (first) {
+ extents.x1 = x1;
+ extents.y1 = y1;
+ extents.x2 = x2;
+ extents.y2 = y2;
+ first = FALSE;
+ } else {
+ if (x1 < extents.x2 && x2 > extents.x1 &&
+ y1 < extents.y2 && y2 > extents.y1)
+ {
+ return TRUE;
+ }
+
+ if (x1 < extents.x1)
+ extents.x1 = x1;
+ if (x2 > extents.x2)
+ extents.x2 = x2;
+ if (y1 < extents.y1)
+ extents.y1 = y1;
+ if (y2 > extents.y2)
+ extents.y2 = y2;
+ }
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ }
+
+ return FALSE;
+}
+
+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
+
+void
+uxa_glyphs (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs)
+{
+ PicturePtr pPicture;
+ PixmapPtr pMaskPixmap = 0;
+ PicturePtr pMask;
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ int width = 0, height = 0;
+ int x, y;
+ int xDst = list->xOff, yDst = list->yOff;
+ int n;
+ GlyphPtr glyph;
+ int error;
+ BoxRec extents = {0, 0, 0, 0};
+ CARD32 component_alpha;
+ uxa_glyph_buffer_t buffer;
+
+ /* If we don't have a mask format but all the glyphs have the same format
+ * and don't intersect, use the glyph format as mask format for the full
+ * benefits of the glyph cache.
+ */
+ if (!maskFormat) {
+ Bool sameFormat = TRUE;
+ int i;
+
+ maskFormat = list[0].format;
+
+ for (i = 0; i < nlist; i++) {
+ if (maskFormat->format != list[i].format->format) {
+ sameFormat = FALSE;
+ break;
+ }
+ }
+
+ if (!sameFormat || (maskFormat->depth != 1 &&
+ uxa_glyphs_intersect(nlist, list, glyphs))) {
+ maskFormat = NULL;
+ }
+ }
+
+ if (maskFormat)
+ {
+ GCPtr pGC;
+ xRectangle rect;
+
+ uxa_glyph_extents (nlist, list, glyphs, &extents);
+
+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
+ return;
+ width = extents.x2 - extents.x1;
+ height = extents.y2 - extents.y1;
+
+ if (maskFormat->depth == 1) {
+ PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8);
+
+ if (a8Format)
+ maskFormat = a8Format;
+ }
+
+ pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ maskFormat->depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pMaskPixmap)
+ return;
+ component_alpha = NeedsComponent(maskFormat->format);
+ pMask = CreatePicture (0, &pMaskPixmap->drawable,
+ maskFormat, CPComponentAlpha, &component_alpha,
+ serverClient, &error);
+ if (!pMask)
+ {
+ (*pScreen->DestroyPixmap) (pMaskPixmap);
+ return;
+ }
+ pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
+ ValidateGC (&pMaskPixmap->drawable, pGC);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
+ FreeScratchGC (pGC);
+ x = -extents.x1;
+ y = -extents.y1;
+ }
+ else
+ {
+ pMask = pDst;
+ x = 0;
+ y = 0;
+ }
+ buffer.count = 0;
+ buffer.source = NULL;
+ while (nlist--)
+ {
+ x += list->xOff;
+ y += list->yOff;
+ n = list->len;
+ while (n--)
+ {
+ glyph = *glyphs++;
+ pPicture = GlyphPicture (glyph)[pScreen->myNum];
+
+ if (glyph->info.width > 0 && glyph->info.height > 0 &&
+ uxa_buffer_glyph(pScreen, &buffer, glyph, x, y) == UXA_GLYPH_NEED_FLUSH)
+ {
+ if (maskFormat)
+ uxa_glyphs_to_mask(pMask, &buffer);
+ else
+ uxa_glyphs_to_dst(op, pSrc, pDst, &buffer,
+ xSrc, ySrc, xDst, yDst);
+
+ uxa_buffer_glyph(pScreen, &buffer, glyph, x, y);
+ }
+
+ x += glyph->info.xOff;
+ y += glyph->info.yOff;
+ }
+ list++;
+ }
+
+ if (maskFormat)
+ uxa_glyphs_to_mask(pMask, &buffer);
+ else
+ uxa_glyphs_to_dst(op, pSrc, pDst, &buffer,
+ xSrc, ySrc, xDst, yDst);
+
+ if (maskFormat)
+ {
+ x = extents.x1;
+ y = extents.y1;
+ CompositePicture (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc + x - xDst,
+ ySrc + y - yDst,
+ 0, 0,
+ x, y,
+ width, height);
+ FreePicture ((pointer) pMask, (XID) 0);
+ (*pScreen->DestroyPixmap) (pMaskPixmap);
+ }
+}
diff --git a/uxa/uxa-priv.h b/uxa/uxa-priv.h
new file mode 100644
index 00000000..acc82bba
--- /dev/null
+++ b/uxa/uxa-priv.h
@@ -0,0 +1,444 @@
+/*
+ *
+ * Copyright © 2000,2008 Keith Packard
+ * 2005 Zack Rusin, Trolltech
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef UXAPRIV_H
+#define UXAPRIV_H
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+
+#include "uxa.h"
+
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#ifdef MITSHM
+#define _XSHM_SERVER_
+#include <X11/extensions/shmstr.h>
+#endif
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "dix.h"
+#include "fb.h"
+#include "fboverlay.h"
+#ifdef RENDER
+//#include "fbpict.h"
+#include "glyphstr.h"
+#endif
+#include "damage.h"
+
+#define DEBUG_TRACE_FALL 0
+#define DEBUG_MIGRATE 0
+#define DEBUG_PIXMAP 0
+#define DEBUG_OFFSCREEN 0
+#define DEBUG_GLYPH_CACHE 0
+
+#if DEBUG_TRACE_FALL
+#define UXA_FALLBACK(x) \
+do { \
+ ErrorF("UXA fallback at %s: ", __FUNCTION__); \
+ ErrorF x; \
+} while (0)
+
+char
+uxa_drawable_location(DrawablePtr pDrawable);
+#else
+#define UXA_FALLBACK(x)
+#endif
+
+#if DEBUG_PIXMAP
+#define DBG_PIXMAP(a) ErrorF a
+#else
+#define DBG_PIXMAP(a)
+#endif
+
+typedef struct {
+ unsigned char sha1[20];
+} uxa_cached_glyph_t;
+
+typedef struct {
+ /* The identity of the cache, statically configured at initialization */
+ unsigned int format;
+ int glyphWidth;
+ int glyphHeight;
+
+ int size; /* Size of cache; eventually this should be dynamically determined */
+
+ /* Hash table mapping from glyph sha1 to position in the glyph; we use
+ * open addressing with a hash table size determined based on size and large
+ * enough so that we always have a good amount of free space, so we can
+ * use linear probing. (Linear probing is preferrable to double hashing
+ * here because it allows us to easily remove entries.)
+ */
+ int *hashEntries;
+ int hashSize;
+
+ uxa_cached_glyph_t *glyphs;
+ int glyphCount; /* Current number of glyphs */
+
+ PicturePtr picture; /* Where the glyphs of the cache are stored */
+ int yOffset; /* y location within the picture where the cache starts */
+ int columns; /* Number of columns the glyphs are layed out in */
+ int evictionPosition; /* Next random position to evict a glyph */
+} uxa_glyph_cache_t;
+
+#define UXA_NUM_GLYPH_CACHES 4
+
+typedef void (*EnableDisableFBAccessProcPtr)(int, Bool);
+typedef struct {
+ uxa_driver_t *info;
+ CreateGCProcPtr SavedCreateGC;
+ CloseScreenProcPtr SavedCloseScreen;
+ GetImageProcPtr SavedGetImage;
+ GetSpansProcPtr SavedGetSpans;
+ CreatePixmapProcPtr SavedCreatePixmap;
+ DestroyPixmapProcPtr SavedDestroyPixmap;
+ CopyWindowProcPtr SavedCopyWindow;
+ ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
+ BitmapToRegionProcPtr SavedBitmapToRegion;
+#ifdef RENDER
+ CompositeProcPtr SavedComposite;
+ TrianglesProcPtr SavedTriangles;
+ GlyphsProcPtr SavedGlyphs;
+ TrapezoidsProcPtr SavedTrapezoids;
+ AddTrapsProcPtr SavedAddTraps;
+#endif
+
+ Bool swappedOut;
+ unsigned disableFbCount;
+ unsigned offScreenCounter;
+
+ uxa_glyph_cache_t glyphCaches[UXA_NUM_GLYPH_CACHES];
+} uxa_screen_t;
+
+/*
+ * This is the only completely portable way to
+ * compute this info.
+ */
+#ifndef BitsPerPixel
+#define BitsPerPixel(d) (\
+ PixmapWidthPaddingInfo[d].notPower2 ? \
+ (PixmapWidthPaddingInfo[d].bytesPerPixel * 8) : \
+ ((1 << PixmapWidthPaddingInfo[d].padBytesLog2) * 8 / \
+ (PixmapWidthPaddingInfo[d].padRoundUp+1)))
+#endif
+
+extern DevPrivateKey uxa_screen_key;
+#define uxa_get_screen(s) ((uxa_screen_t *)dixLookupPrivate(&(s)->devPrivates, uxa_screen_key))
+
+/** Align an offset to an arbitrary alignment */
+#define UXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
+ (((offset) + (align) - 1) % (align)))
+/** Align an offset to a power-of-two alignment */
+#define UXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
+
+typedef struct {
+ INT16 xSrc;
+ INT16 ySrc;
+ INT16 xDst;
+ INT16 yDst;
+ INT16 width;
+ INT16 height;
+} uxa_composite_rect_t;
+
+/**
+ * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
+ * to set EXA options or hook in screen functions to handle using EXA as the AA.
+ */
+void exaDDXDriverInit (ScreenPtr pScreen);
+
+void
+uxa_prepare_access_window(WindowPtr pWin);
+
+void
+uxa_finish_access_window(WindowPtr pWin);
+
+/* uxa-unaccel.c */
+void
+uxa_prepare_access_gc(GCPtr pGC);
+
+void
+uxa_finish_access_gc(GCPtr pGC);
+
+void
+uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted);
+
+void
+uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
+
+void
+uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits);
+
+RegionPtr
+uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty);
+
+RegionPtr
+uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane);
+
+void
+uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit);
+
+void
+uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt);
+
+void
+uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit);
+
+void
+uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs);
+
+void
+uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect);
+
+void
+uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase);
+
+void
+uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y);
+
+void
+uxa_check_get_spans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart);
+
+void
+uxa_check_add_traps (PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off,
+ int ntrap,
+ xTrap *traps);
+
+/* uxa-accel.c */
+
+static _X_INLINE Bool
+uxa_gc_reads_destination(DrawablePtr pDrawable, unsigned long planemask,
+ unsigned int fillStyle, unsigned char alu)
+{
+ return ((alu != GXcopy && alu != GXclear &&alu != GXset &&
+ alu != GXcopyInverted) || fillStyle == FillStippled ||
+ !UXA_PM_IS_SOLID(pDrawable, planemask));
+}
+
+void
+uxa_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
+
+Bool
+uxa_fill_region_tiled (DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
+ DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu);
+
+void
+uxa_shm_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, unsigned int format,
+ int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
+ char *data);
+
+void
+uxa_get_image (DrawablePtr pDrawable, int x, int y, int w, int h,
+ unsigned int format, unsigned long planeMask, char *d);
+
+extern const GCOps uxa_ops;
+
+#ifdef MITSHM
+extern ShmFuncs uxa_shm_funcs;
+
+/* XXX these come from shmint.h, which isn't exported by the server */
+void
+ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs);
+
+void
+ShmSetPixmapFormat(ScreenPtr pScreen, int format);
+
+void
+fbShmPutImage(XSHM_PUT_IMAGE_ARGS);
+
+#endif
+
+#ifdef RENDER
+
+/* XXX these are in fbpict.h, which is not installed */
+void
+fbComposite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+
+void
+fbAddTraps (PicturePtr pPicture,
+ INT16 xOff,
+ INT16 yOff,
+ int ntrap,
+ xTrap *traps);
+
+void
+uxa_check_composite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+#endif
+
+/* uxa.c */
+void
+uxa_prepare_access(DrawablePtr pDrawable, int index);
+
+void
+uxa_finish_access(DrawablePtr pDrawable, int index);
+
+void
+uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+ int *xp, int *yp);
+
+Bool
+uxa_drawable_is_offscreen (DrawablePtr pDrawable);
+
+Bool
+uxa_pixmap_is_offscreen(PixmapPtr p);
+
+PixmapPtr
+uxa_get_offscreen_pixmap (DrawablePtr pDrawable, int *xp, int *yp);
+
+PixmapPtr
+uxa_get_drawable_pixmap(DrawablePtr pDrawable);
+
+RegionPtr
+uxa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+ int srcx, int srcy, int width, int height, int dstx, int dsty);
+
+void
+uxa_copy_n_to_n (DrawablePtr pSrcDrawable,
+ DrawablePtr pDstDrawable,
+ GCPtr pGC,
+ BoxPtr pbox,
+ int nbox,
+ int dx,
+ int dy,
+ Bool reverse,
+ Bool upsidedown,
+ Pixel bitplane,
+ void *closure);
+
+/* uxa_render.c */
+Bool
+uxa_op_reads_destination (CARD8 op);
+
+void
+uxa_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height);
+
+void
+uxa_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects);
+
+void
+uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntrap, xTrapezoid *traps);
+
+void
+uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntri, xTriangle *tris);
+
+/* uxa_glyph.c */
+void
+uxa_glyphs_init(ScreenPtr pScreen);
+
+void
+uxa_glyphs_fini (ScreenPtr pScreen);
+
+void
+uxa_glyphs (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ PictFormatPtr maskFormat,
+ INT16 xSrc,
+ INT16 ySrc,
+ int nlist,
+ GlyphListPtr list,
+ GlyphPtr *glyphs);
+
+#endif /* UXAPRIV_H */
diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c
new file mode 100644
index 00000000..38e6088f
--- /dev/null
+++ b/uxa/uxa-render.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+
+#if DEBUG_TRACE_FALL
+static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string, int n)
+{
+ char format[20];
+ char size[20];
+ char loc;
+ int temp;
+
+ if (!pict) {
+ snprintf(string, n, "None");
+ return;
+ }
+
+ switch (pict->format)
+ {
+ case PICT_a8r8g8b8:
+ snprintf(format, 20, "ARGB8888");
+ break;
+ case PICT_x8r8g8b8:
+ snprintf(format, 20, "XRGB8888");
+ break;
+ case PICT_r5g6b5:
+ snprintf(format, 20, "RGB565 ");
+ break;
+ case PICT_x1r5g5b5:
+ snprintf(format, 20, "RGB555 ");
+ break;
+ case PICT_a8:
+ snprintf(format, 20, "A8 ");
+ break;
+ case PICT_a1:
+ snprintf(format, 20, "A1 ");
+ break;
+ default:
+ snprintf(format, 20, "0x%x", (int)pict->format);
+ break;
+ }
+
+ loc = uxa_get_drawable_pixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
+
+ snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
+ pict->pDrawable->height, pict->repeat ?
+ " R" : "");
+
+ snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
+}
+
+static void
+uxa_print_composite_fallback(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst)
+{
+ char sop[20];
+ char srcdesc[40], maskdesc[40], dstdesc[40];
+
+ switch(op)
+ {
+ case PictOpSrc:
+ sprintf(sop, "Src");
+ break;
+ case PictOpOver:
+ sprintf(sop, "Over");
+ break;
+ default:
+ sprintf(sop, "0x%x", (int)op);
+ break;
+ }
+
+ uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
+ uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
+ uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
+
+ ErrorF("Composite fallback: op %s, \n"
+ " src %s, \n"
+ " mask %s, \n"
+ " dst %s, \n",
+ sop, srcdesc, maskdesc, dstdesc);
+}
+#endif /* DEBUG_TRACE_FALL */
+
+Bool
+uxa_op_reads_destination (CARD8 op)
+{
+ /* FALSE (does not read destination) is the list of ops in the protocol
+ * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
+ * That's just Clear and Src. ReduceCompositeOp() will already have
+ * converted con/disjoint clear/src to Clear or Src.
+ */
+ switch (op) {
+ case PictOpClear:
+ case PictOpSrc:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+
+static Bool
+uxa_get_pixel_from_rgba(CARD32 *pixel,
+ CARD16 red,
+ CARD16 green,
+ CARD16 blue,
+ CARD16 alpha,
+ CARD32 format)
+{
+ int rbits, bbits, gbits, abits;
+ int rshift, bshift, gshift, ashift;
+
+ *pixel = 0;
+
+ if (!PICT_FORMAT_COLOR(format))
+ return FALSE;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else { /* PICT_TYPE_ABGR */
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ }
+
+ *pixel |= ( blue >> (16 - bbits)) << bshift;
+ *pixel |= ( red >> (16 - rbits)) << rshift;
+ *pixel |= (green >> (16 - gbits)) << gshift;
+ *pixel |= (alpha >> (16 - abits)) << ashift;
+
+ return TRUE;
+}
+
+static Bool
+uxa_get_rgba_from_pixel(CARD32 pixel,
+ CARD16 *red,
+ CARD16 *green,
+ CARD16 *blue,
+ CARD16 *alpha,
+ CARD32 format)
+{
+ int rbits, bbits, gbits, abits;
+ int rshift, bshift, gshift, ashift;
+
+ if (!PICT_FORMAT_COLOR(format))
+ return FALSE;
+
+ rbits = PICT_FORMAT_R(format);
+ gbits = PICT_FORMAT_G(format);
+ bbits = PICT_FORMAT_B(format);
+ abits = PICT_FORMAT_A(format);
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+ bshift = 0;
+ gshift = bbits;
+ rshift = gshift + gbits;
+ ashift = rshift + rbits;
+ } else { /* PICT_TYPE_ABGR */
+ rshift = 0;
+ gshift = rbits;
+ bshift = gshift + gbits;
+ ashift = bshift + bbits;
+ }
+
+ *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
+ while (rbits < 16) {
+ *red |= *red >> rbits;
+ rbits <<= 1;
+ }
+
+ *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
+ while (gbits < 16) {
+ *green |= *green >> gbits;
+ gbits <<= 1;
+ }
+
+ *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
+ while (bbits < 16) {
+ *blue |= *blue >> bbits;
+ bbits <<= 1;
+ }
+
+ if (abits) {
+ *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
+ while (abits < 16) {
+ *alpha |= *alpha >> abits;
+ abits <<= 1;
+ }
+ } else
+ *alpha = 0xffff;
+
+ return TRUE;
+}
+
+static int
+uxa_try_driver_solid_fill(PicturePtr pSrc,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+ int dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pDstPix;
+ CARD32 pixel;
+ CARD16 red, green, blue, alpha;
+
+ pDstPix = uxa_get_drawable_pixmap (pDst->pDrawable);
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ width, height))
+ return 1;
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ pixel = uxa_get_pixmap_first_pixel (pSrcPix);
+
+ if (!uxa_pixmap_is_offscreen(pDstPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!uxa_get_rgba_from_pixel(pixel, &red, &green, &blue, &alpha,
+ pSrc->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!uxa_get_pixel_from_rgba(&pixel, red, green, blue, alpha,
+ pDst->format))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ if (!(*uxa_screen->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
+ pbox++;
+ }
+
+ (*uxa_screen->info->DoneSolid) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+static int
+uxa_try_driver_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pDstPix;
+ struct _Pixmap scratch;
+
+ if (!uxa_screen->info->PrepareComposite)
+ return -1;
+
+ pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
+
+ pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable);
+
+ if (uxa_screen->info->CheckComposite &&
+ !(*uxa_screen->info->CheckComposite) (op, pSrc, NULL, pDst))
+ {
+ return -1;
+ }
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (!uxa_pixmap_is_offscreen(pDstPix))
+ return 0;
+
+ if (!pSrcPix && uxa_screen->info->UploadToScratch)
+ {
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch))
+ pSrcPix = &scratch;
+ }
+
+ if (!pSrcPix)
+ return 0;
+
+ if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix,
+ NULL, pDstPix))
+ return -1;
+
+ while (nrect--)
+ {
+ INT16 xDst = rects->xDst + pDst->pDrawable->x;
+ INT16 yDst = rects->yDst + pDst->pDrawable->y;
+ INT16 xSrc = rects->xSrc + pSrc->pDrawable->x;
+ INT16 ySrc = rects->ySrc + pSrc->pDrawable->y;
+
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+
+ if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
+ xSrc, ySrc, 0, 0, xDst, yDst,
+ rects->width, rects->height))
+ goto next_rect;
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ xSrc = xSrc + src_off_x - xDst - dst_off_x;
+ ySrc = ySrc + src_off_y - yDst - dst_off_y;
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Composite) (pDstPix,
+ pbox->x1 + xSrc,
+ pbox->y1 + ySrc,
+ 0, 0,
+ pbox->x1,
+ pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+
+ next_rect:
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+
+ rects++;
+ }
+
+ (*uxa_screen->info->DoneComposite) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ return 1;
+}
+
+/**
+ * Copy a number of rectangles from source to destination in a single
+ * operation. This is specialized for building a glyph mask: we don'y
+ * have a mask argument because we don't need it for that, and we
+ * don't have he special-case fallbacks found in uxa_composite() - if the
+ * driver can support it, we use the driver functionality, otherwise we
+ * fallback straight to software.
+ */
+void
+uxa_composite_rects(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pDst,
+ int nrect,
+ uxa_composite_rect_t *rects)
+{
+ int n;
+ uxa_composite_rect_t *r;
+
+ /************************************************************/
+
+ ValidatePicture (pSrc);
+ ValidatePicture (pDst);
+
+ if (uxa_try_driver_composite_rects(op, pSrc, pDst, nrect, rects) != 1) {
+ n = nrect;
+ r = rects;
+ while (n--) {
+ uxa_check_composite (op, pSrc, NULL, pDst,
+ r->xSrc, r->ySrc,
+ 0, 0,
+ r->xDst, r->yDst,
+ r->width, r->height);
+ r++;
+ }
+ }
+
+ /************************************************************/
+
+}
+
+static int
+uxa_try_driver_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ RegionRec region;
+ BoxPtr pbox;
+ int nbox;
+ int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
+ PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
+ struct _Pixmap scratch;
+
+ pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
+ pDstPix = uxa_get_drawable_pixmap(pDst->pDrawable);
+ if (pMask)
+ pMaskPix = uxa_get_drawable_pixmap(pMask->pDrawable);
+
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+
+ if (pMask) {
+ xMask += pMask->pDrawable->x;
+ yMask += pMask->pDrawable->y;
+ }
+
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (uxa_screen->info->CheckComposite &&
+ !(*uxa_screen->info->CheckComposite) (op, pSrc, pMask, pDst))
+ {
+ return -1;
+ }
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ return 1;
+
+ uxa_get_drawable_deltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
+
+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
+
+ pSrcPix = uxa_get_offscreen_pixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
+ if (pMask)
+ pMaskPix = uxa_get_offscreen_pixmap (pMask->pDrawable, &mask_off_x,
+ &mask_off_y);
+
+ if (!uxa_pixmap_is_offscreen(pDstPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!pSrcPix && (!pMask || pMaskPix) && uxa_screen->info->UploadToScratch) {
+ pSrcPix = uxa_get_drawable_pixmap (pSrc->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pSrcPix, &scratch))
+ pSrcPix = &scratch;
+ } else if (pSrcPix && pMask && !pMaskPix && uxa_screen->info->UploadToScratch) {
+ pMaskPix = uxa_get_drawable_pixmap (pMask->pDrawable);
+ if ((*uxa_screen->info->UploadToScratch) (pMaskPix, &scratch))
+ pMaskPix = &scratch;
+ }
+
+ if (!pSrcPix || (pMask && !pMaskPix)) {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 0;
+ }
+
+ if (!(*uxa_screen->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
+ pMaskPix, pDstPix))
+ {
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return -1;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ pbox = REGION_RECTS(&region);
+
+ xMask = xMask + mask_off_x - xDst - dst_off_x;
+ yMask = yMask + mask_off_y - yDst - dst_off_y;
+
+ xSrc = xSrc + src_off_x - xDst - dst_off_x;
+ ySrc = ySrc + src_off_y - yDst - dst_off_y;
+
+ while (nbox--)
+ {
+ (*uxa_screen->info->Composite) (pDstPix,
+ pbox->x1 + xSrc,
+ pbox->y1 + ySrc,
+ pbox->x1 + xMask,
+ pbox->y1 + yMask,
+ pbox->x1,
+ pbox->y1,
+ pbox->x2 - pbox->x1,
+ pbox->y2 - pbox->y1);
+ pbox++;
+ }
+ (*uxa_screen->info->DoneComposite) (pDstPix);
+ uxa_mark_sync(pDst->pDrawable->pScreen);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ return 1;
+}
+
+/**
+ * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
+ * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
+ * alpha and limited 1-tmu cards.
+ *
+ * From http://anholt.livejournal.com/32058.html:
+ *
+ * The trouble is that component-alpha rendering requires two different sources
+ * for blending: one for the source value to the blender, which is the
+ * per-channel multiplication of source and mask, and one for the source alpha
+ * for multiplying with the destination channels, which is the multiplication
+ * of the source channels by the mask alpha. So the equation for Over is:
+ *
+ * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
+ * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
+ * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
+ * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
+ *
+ * But we can do some simpler operations, right? How about PictOpOutReverse,
+ * which has a source factor of 0 and dest factor of (1 - source alpha). We
+ * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
+ * blenders pretty easily. So we can do a component-alpha OutReverse, which
+ * gets us:
+ *
+ * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
+ * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
+ * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
+ * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
+ *
+ * OK. And if an op doesn't use the source alpha value for the destination
+ * factor, then we can do the channel multiplication in the texture blenders
+ * to get the source value, and ignore the source alpha that we wouldn't use.
+ * We've supported this in the Radeon driver for a long time. An example would
+ * be PictOpAdd, which does:
+ *
+ * dst.A = src.A * mask.A + dst.A
+ * dst.R = src.R * mask.R + dst.R
+ * dst.G = src.G * mask.G + dst.G
+ * dst.B = src.B * mask.B + dst.B
+ *
+ * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
+ * after it, we get:
+ *
+ * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
+ * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
+ * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
+ * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
+ */
+
+static int
+uxa_try_magic_two_pass_composite_helper(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+
+ assert(op == PictOpOver);
+
+ if (uxa_screen->info->CheckComposite &&
+ (!(*uxa_screen->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
+ pDst) ||
+ !(*uxa_screen->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
+ {
+ return -1;
+ }
+
+ /* Now, we think we should be able to accelerate this operation. First,
+ * composite the destination to be the destination times the source alpha
+ * factors.
+ */
+ uxa_composite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ xDst, yDst, width, height);
+
+ /* Then, add in the source value times the destination alpha factors (1.0).
+ */
+ uxa_composite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+ xDst, yDst, width, height);
+
+ return 1;
+}
+
+void
+uxa_composite(CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
+ int ret = -1;
+ Bool saveSrcRepeat = pSrc->repeat;
+ Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
+ RegionRec region;
+
+ /* We currently don't support acceleration of gradients, or other pictures
+ * with a NULL pDrawable.
+ */
+ if (uxa_screen->swappedOut ||
+ pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL))
+ {
+ goto fallback;
+ }
+
+ /* Remove repeat in source if useless */
+ if (pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
+ (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
+ (ySrc + height) <= pSrc->pDrawable->height)
+ pSrc->repeat = 0;
+
+ if (!pMask)
+ {
+ if ((op == PictOpSrc &&
+ ((pSrc->format == pDst->format) ||
+ (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) ||
+ (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) ||
+ (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap &&
+ pSrc->format == pDst->format &&
+ (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8)))
+ {
+ if (pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat)
+ {
+ ret = uxa_try_driver_solid_fill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+ else if (pSrc->pDrawable != NULL &&
+ !pSrc->repeat &&
+ !pSrc->transform)
+ {
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
+ xSrc, ySrc, xMask, yMask, xDst,
+ yDst, width, height))
+ goto done;
+
+
+ uxa_copy_n_to_n (pSrc->pDrawable, pDst->pDrawable, NULL,
+ REGION_RECTS(&region), REGION_NUM_RECTS(&region),
+ xSrc - xDst, ySrc - yDst,
+ FALSE, FALSE, 0, NULL);
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+ goto done;
+ }
+ else if (pSrc->pDrawable != NULL &&
+ pSrc->pDrawable->type == DRAWABLE_PIXMAP &&
+ !pSrc->transform &&
+ pSrc->repeatType == RepeatNormal)
+ {
+ DDXPointRec patOrg;
+
+ /* Let's see if the driver can do the repeat in one go */
+ if (uxa_screen->info->PrepareComposite && !pSrc->alphaMap &&
+ !pDst->alphaMap)
+ {
+ ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc,
+ ySrc, xMask, yMask, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+
+ /* Now see if we can use uxa_fill_region_tiled() */
+ xDst += pDst->pDrawable->x;
+ yDst += pDst->pDrawable->y;
+ xSrc += pSrc->pDrawable->x;
+ ySrc += pSrc->pDrawable->y;
+
+ if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, xSrc,
+ ySrc, xMask, yMask, xDst, yDst,
+ width, height))
+ goto done;
+
+ /* pattern origin is the point in the destination drawable
+ * corresponding to (0,0) in the source */
+ patOrg.x = xDst - xSrc;
+ patOrg.y = yDst - ySrc;
+
+ ret = uxa_fill_region_tiled(pDst->pDrawable, &region,
+ (PixmapPtr)pSrc->pDrawable,
+ &patOrg, FB_ALLONES, GXcopy);
+
+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
+
+ if (ret)
+ goto done;
+ }
+ }
+ }
+
+ /* Remove repeat in mask if useless */
+ if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 &&
+ (xMask + width) <= pMask->pDrawable->width && yMask >= 0 &&
+ (yMask + height) <= pMask->pDrawable->height)
+ pMask->repeat = 0;
+
+ if (uxa_screen->info->PrepareComposite &&
+ !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
+ {
+ Bool isSrcSolid;
+
+ ret = uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
+ yMask, xDst, yDst, width, height);
+ if (ret == 1)
+ goto done;
+
+ /* For generic masks and solid src pictures, mach64 can do Over in two
+ * passes, similar to the component-alpha case.
+ */
+ isSrcSolid = pSrc->pDrawable->width == 1 &&
+ pSrc->pDrawable->height == 1 &&
+ pSrc->repeat;
+
+ /* If we couldn't do the Composite in a single pass, and it was a
+ * component-alpha Over, see if we can do it in two passes with
+ * an OutReverse and then an Add.
+ */
+ if (ret == -1 && op == PictOpOver && pMask &&
+ (pMask->componentAlpha || isSrcSolid)) {
+ ret = uxa_try_magic_two_pass_composite_helper(op, pSrc, pMask, pDst,
+ xSrc, ySrc,
+ xMask, yMask, xDst, yDst,
+ width, height);
+ if (ret == 1)
+ goto done;
+ }
+ }
+
+fallback:
+#if DEBUG_TRACE_FALL
+ uxa_print_composite_fallback (op, pSrc, pMask, pDst);
+#endif
+
+ uxa_check_composite (op, pSrc, pMask, pDst, xSrc, ySrc,
+ xMask, yMask, xDst, yDst, width, height);
+
+done:
+ pSrc->repeat = saveSrcRepeat;
+ if (pMask)
+ pMask->repeat = saveMaskRepeat;
+}
+#endif
+
+/**
+ * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
+ * of PolyFillRect to initialize the pixmap after creating it, to prevent
+ * the pixmap from being migrated.
+ *
+ * See the comments about uxa_trapezoids and uxa_triangles.
+ */
+static PicturePtr
+uxa_create_alpha_picture (ScreenPtr pScreen,
+ PicturePtr pDst,
+ PictFormatPtr pPictFormat,
+ CARD16 width,
+ CARD16 height)
+{
+ PixmapPtr pPixmap;
+ PicturePtr pPicture;
+ GCPtr pGC;
+ int error;
+ xRectangle rect;
+
+ if (width > 32767 || height > 32767)
+ return 0;
+
+ if (!pPictFormat)
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ if (!pPictFormat)
+ return 0;
+ }
+
+ pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+ pPictFormat->depth, 0);
+ if (!pPixmap)
+ return 0;
+ pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
+ if (!pGC)
+ {
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return 0;
+ }
+ ValidateGC (&pPixmap->drawable, pGC);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ uxa_check_poly_fill_rect (&pPixmap->drawable, pGC, 1, &rect);
+ FreeScratchGC (pGC);
+ pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
+ 0, 0, serverClient, &error);
+ (*pScreen->DestroyPixmap) (pPixmap);
+ return pPicture;
+}
+
+/**
+ * uxa_trapezoids is essentially a copy of miTrapezoids that uses
+ * uxa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to RasterizeTrapezoid won't be accelerated however, which
+ * forces the pixmap to be moved out again.
+ *
+ * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect
+ * to initialize the contents.
+ */
+void
+uxa_trapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntrap, xTrapezoid *traps)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+ BoxRec bounds;
+ Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
+
+ if (maskFormat || direct) {
+ miTrapezoidBounds (ntrap, traps, &bounds);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return;
+ }
+
+ /*
+ * Check for solid alpha add
+ */
+ if (direct)
+ {
+ DrawablePtr pDraw = pDst->pDrawable;
+ PixmapPtr pixmap = uxa_get_drawable_pixmap (pDraw);
+ int xoff, yoff;
+
+ uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
+
+ xoff += pDraw->x;
+ yoff += pDraw->y;
+
+ uxa_prepare_access(pDraw, UXA_PREPARE_DEST);
+
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
+
+ uxa_finish_access(pDraw, UXA_PREPARE_DEST);
+ }
+ else if (maskFormat)
+ {
+ PicturePtr pPicture;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+
+ xDst = traps[0].left.p1.x >> 16;
+ yDst = traps[0].left.p1.y >> 16;
+
+ pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ if (!pPicture)
+ return;
+
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ for (; ntrap; ntrap--, traps++)
+ (*ps->RasterizeTrapezoid) (pPicture, traps,
+ -bounds.x1, -bounds.y1);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+
+ xRel = bounds.x1 + xSrc - xDst;
+ yRel = bounds.y1 + ySrc - yDst;
+ CompositePicture (op, pSrc, pPicture, pDst,
+ xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ FreePicture (pPicture, 0);
+ }
+ else
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+ for (; ntrap; ntrap--, traps++)
+ uxa_trapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
+ }
+}
+
+/**
+ * uxa_triangles is essentially a copy of miTriangles that uses
+ * uxa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to AddTriangles won't be accelerated however, which forces the pixmap
+ * to be moved out again.
+ *
+ * uxa_create_alpha_picture avoids this roundtrip by using uxa_check_poly_fill_rect
+ * to initialize the contents.
+ */
+void
+uxa_triangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+ PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+ int ntri, xTriangle *tris)
+{
+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
+ PictureScreenPtr ps = GetPictureScreen(pScreen);
+ BoxRec bounds;
+ Bool direct = op == PictOpAdd && miIsSolidAlpha (pSrc);
+
+ if (maskFormat || direct) {
+ miTriangleBounds (ntri, tris, &bounds);
+
+ if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+ return;
+ }
+
+ /*
+ * Check for solid alpha add
+ */
+ if (direct)
+ {
+ DrawablePtr pDraw = pDst->pDrawable;
+ uxa_prepare_access(pDraw, UXA_PREPARE_DEST);
+ (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
+ uxa_finish_access(pDraw, UXA_PREPARE_DEST);
+ }
+ else if (maskFormat)
+ {
+ PicturePtr pPicture;
+ INT16 xDst, yDst;
+ INT16 xRel, yRel;
+
+ xDst = tris[0].p1.x >> 16;
+ yDst = tris[0].p1.y >> 16;
+
+ pPicture = uxa_create_alpha_picture (pScreen, pDst, maskFormat,
+ bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1);
+ if (!pPicture)
+ return;
+
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+
+ xRel = bounds.x1 + xSrc - xDst;
+ yRel = bounds.y1 + ySrc - yDst;
+ CompositePicture (op, pSrc, pPicture, pDst,
+ xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+ bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+ FreePicture (pPicture, 0);
+ }
+ else
+ {
+ if (pDst->polyEdge == PolyEdgeSharp)
+ maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
+ else
+ maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
+
+ for (; ntri; ntri--, tris++)
+ uxa_triangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
+ }
+}
diff --git a/uxa/uxa-unaccel.c b/uxa/uxa-unaccel.c
new file mode 100644
index 00000000..27194208
--- /dev/null
+++ b/uxa/uxa-unaccel.c
@@ -0,0 +1,370 @@
+/*
+ *
+ * Copyright © 1999 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uxa-priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#endif
+
+/*
+ * These functions wrap the low-level fb rendering functions and
+ * synchronize framebuffer/accelerated drawing by stalling until
+ * the accelerator is idle
+ */
+
+/**
+ * Calls uxa_prepare_access with UXA_PREPARE_SRC for the tile, if that is the
+ * current fill style.
+ *
+ * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
+ * 1bpp and never in fb, so we don't worry about them.
+ * We should worry about them for completeness sake and going forward.
+ */
+void
+uxa_prepare_access_gc(GCPtr pGC)
+{
+ if (pGC->stipple)
+ uxa_prepare_access(&pGC->stipple->drawable, UXA_PREPARE_MASK);
+ if (pGC->fillStyle == FillTiled)
+ uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+/**
+ * Finishes access to the tile in the GC, if used.
+ */
+void
+uxa_finish_access_gc(GCPtr pGC)
+{
+ if (pGC->fillStyle == FillTiled)
+ uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_MASK);
+ if (pGC->stipple)
+ uxa_finish_access(&pGC->stipple->drawable, UXA_PREPARE_SRC);
+}
+
+#if DEBUG_TRACE_FALL
+char
+uxa_drawable_location(DrawablePtr pDrawable)
+{
+ return uxa_drawable_is_offscreen(pDrawable) ? 's' : 'm';
+}
+#endif /* DEBUG_TRACE_FALL */
+
+void
+uxa_check_fill_spans (DrawablePtr pDrawable, GCPtr pGC, int nspans,
+ DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbFillSpans (pDrawable, pGC, nspans, ppt, pwidth, fSorted);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_set_spans (DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+ DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbSetSpans (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_put_image (DrawablePtr pDrawable, GCPtr pGC, int depth,
+ int x, int y, int w, int h, int leftPad, int format,
+ char *bits)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+RegionPtr
+uxa_check_copy_area (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+ RegionPtr ret;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc), uxa_drawable_location(pDst)));
+ uxa_prepare_access (pDst, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrc, UXA_PREPARE_SRC);
+ ret = fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+ uxa_finish_access (pSrc, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst, UXA_PREPARE_DEST);
+
+ return ret;
+}
+
+RegionPtr
+uxa_check_copy_plane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+ int srcx, int srcy, int w, int h, int dstx, int dsty,
+ unsigned long bitPlane)
+{
+ RegionPtr ret;
+
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+ uxa_drawable_location(pSrc), uxa_drawable_location(pDst)));
+ uxa_prepare_access (pDst, UXA_PREPARE_DEST);
+ uxa_prepare_access (pSrc, UXA_PREPARE_SRC);
+ ret = fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
+ bitPlane);
+ uxa_finish_access (pSrc, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst, UXA_PREPARE_DEST);
+
+ return ret;
+}
+
+void
+uxa_check_poly_point (DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ fbPolyPoint (pDrawable, pGC, mode, npt, pptInit);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_poly_lines (DrawablePtr pDrawable, GCPtr pGC,
+ int mode, int npt, DDXPointPtr ppt)
+{
+ UXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
+ pDrawable, uxa_drawable_location(pDrawable),
+ pGC->lineWidth, mode, npt));
+
+ if (pGC->lineWidth == 0) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolyLine (pDrawable, pGC, mode, npt, ppt);
+}
+
+void
+uxa_check_poly_segment (DrawablePtr pDrawable, GCPtr pGC,
+ int nsegInit, xSegment *pSegInit)
+{
+ UXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->lineWidth, nsegInit));
+ if (pGC->lineWidth == 0) {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+ /* fb calls mi functions in the lineWidth != 0 case. */
+ fbPolySegment (pDrawable, pGC, nsegInit, pSegInit);
+}
+
+void
+uxa_check_poly_arc (DrawablePtr pDrawable, GCPtr pGC,
+ int narcs, xArc *pArcs)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+
+ /* Disable this as fbPolyArc can call miZeroPolyArc which in turn
+ * can call accelerated functions, that as yet, haven't been notified
+ * with uxa_finish_access().
+ */
+#if 0
+ if (pGC->lineWidth == 0)
+ {
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyArc (pDrawable, pGC, narcs, pArcs);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+ return;
+ }
+#endif
+ miPolyArc (pDrawable, pGC, narcs, pArcs);
+}
+
+void
+uxa_check_poly_fill_rect (DrawablePtr pDrawable, GCPtr pGC,
+ int nrect, xRectangle *prect)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyFillRect (pDrawable, pGC, nrect, prect);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_image_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ UXA_FALLBACK(("to %p (%c)\n", pDrawable,
+ uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_poly_glyph_blt (DrawablePtr pDrawable, GCPtr pGC,
+ int x, int y, unsigned int nglyph,
+ CharInfoPtr *ppci, pointer pglyphBase)
+{
+ UXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
+ uxa_drawable_location(pDrawable), pGC->fillStyle, pGC->alu));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access_gc (pGC);
+ fbPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_push_pixels (GCPtr pGC, PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w, int h, int x, int y)
+{
+ UXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
+ uxa_drawable_location(&pBitmap->drawable),
+ uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_DEST);
+ uxa_prepare_access (&pBitmap->drawable, UXA_PREPARE_SRC);
+ uxa_prepare_access_gc (pGC);
+ fbPushPixels (pGC, pBitmap, pDrawable, w, h, x, y);
+ uxa_finish_access_gc (pGC);
+ uxa_finish_access (&pBitmap->drawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_get_spans (DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pdstStart)
+{
+ UXA_FALLBACK(("from %p (%c)\n", pDrawable, uxa_drawable_location(pDrawable)));
+ uxa_prepare_access (pDrawable, UXA_PREPARE_SRC);
+ fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+ uxa_finish_access (pDrawable, UXA_PREPARE_SRC);
+}
+
+void
+uxa_check_composite (CARD8 op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst,
+ INT16 xSrc,
+ INT16 ySrc,
+ INT16 xMask,
+ INT16 yMask,
+ INT16 xDst,
+ INT16 yDst,
+ CARD16 width,
+ CARD16 height)
+{
+ UXA_FALLBACK(("from picts %p/%p to pict %p\n",
+ pSrc, pMask, pDst));
+
+ uxa_prepare_access (pDst->pDrawable, UXA_PREPARE_DEST);
+ if (pSrc->pDrawable != NULL)
+ uxa_prepare_access (pSrc->pDrawable, UXA_PREPARE_SRC);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_prepare_access (pMask->pDrawable, UXA_PREPARE_MASK);
+ fbComposite (op,
+ pSrc,
+ pMask,
+ pDst,
+ xSrc,
+ ySrc,
+ xMask,
+ yMask,
+ xDst,
+ yDst,
+ width,
+ height);
+ if (pMask && pMask->pDrawable != NULL)
+ uxa_finish_access (pMask->pDrawable, UXA_PREPARE_MASK);
+ if (pSrc->pDrawable != NULL)
+ uxa_finish_access (pSrc->pDrawable, UXA_PREPARE_SRC);
+ uxa_finish_access (pDst->pDrawable, UXA_PREPARE_DEST);
+}
+
+void
+uxa_check_add_traps (PicturePtr pPicture,
+ INT16 x_off,
+ INT16 y_off,
+ int ntrap,
+ xTrap *traps)
+{
+ UXA_FALLBACK(("to pict %p (%c)\n",
+ uxa_drawable_location(pPicture->pDrawable)));
+ uxa_prepare_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+ fbAddTraps (pPicture, x_off, y_off, ntrap, traps);
+ uxa_finish_access(pPicture->pDrawable, UXA_PREPARE_DEST);
+}
+
+/**
+ * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
+ * that happen to be 1x1. Pixmap must be at least 8bpp.
+ *
+ * XXX This really belongs in fb, so it can be aware of tiling and etc.
+ */
+CARD32
+uxa_get_pixmap_first_pixel (PixmapPtr pPixmap)
+{
+ CARD32 pixel;
+ void *fb;
+
+ uxa_prepare_access (&pPixmap->drawable, UXA_PREPARE_SRC);
+ fb = pPixmap->devPrivate.ptr;
+
+ switch (pPixmap->drawable.bitsPerPixel) {
+ case 32:
+ pixel = *(CARD32 *)fb;
+ break;
+ case 16:
+ pixel = *(CARD16 *)fb;
+ break;
+ default:
+ pixel = *(CARD8 *)fb;
+ break;
+ }
+ uxa_finish_access(&pPixmap->drawable, UXA_PREPARE_SRC);
+
+ return pixel;
+}
diff --git a/uxa/uxa.c b/uxa/uxa.c
new file mode 100644
index 00000000..9745f8bb
--- /dev/null
+++ b/uxa/uxa.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/** @file
+ * This file covers the initialization and teardown of UXA, and has various
+ * functions not responsible for performing rendering, pixmap migration, or
+ * memory management.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "uxa-priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "uxa.h"
+
+DevPrivateKey uxa_screen_key = &uxa_screen_key;
+
+/**
+ * uxa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
+ *
+ * @param pDrawable the drawable being requested.
+ *
+ * This function returns the backing pixmap for a drawable, whether it is a
+ * redirected window, unredirected window, or already a pixmap. Note that
+ * coordinate translation is needed when drawing to the backing pixmap of a
+ * redirected window, and the translation coordinates are provided by calling
+ * uxa_get_drawable_pixmap() on the drawable.
+ */
+PixmapPtr
+uxa_get_drawable_pixmap(DrawablePtr pDrawable)
+{
+ if (pDrawable->type == DRAWABLE_WINDOW)
+ return pDrawable->pScreen->GetWindowPixmap ((WindowPtr) pDrawable);
+ else
+ return (PixmapPtr) pDrawable;
+}
+
+/**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+void
+uxa_get_drawable_deltas (DrawablePtr pDrawable, PixmapPtr pPixmap,
+ int *xp, int *yp)
+{
+#ifdef COMPOSITE
+ if (pDrawable->type == DRAWABLE_WINDOW) {
+ *xp = -pPixmap->screen_x;
+ *yp = -pPixmap->screen_y;
+ return;
+ }
+#endif
+
+ *xp = 0;
+ *yp = 0;
+}
+
+/**
+ * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen
+ * memory, meaning that acceleration could probably be done to it, and that it
+ * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
+ * with the CPU.
+ *
+ * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly
+ * deal with moving pixmaps in and out of system memory), UXA will give drivers
+ * pixmaps as arguments for which uxa_pixmap_is_offscreen() is TRUE.
+ *
+ * @return TRUE if the given drawable is in framebuffer memory.
+ */
+Bool
+uxa_pixmap_is_offscreen(PixmapPtr p)
+{
+ ScreenPtr pScreen = p->drawable.pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ if (uxa_screen->info->PixmapIsOffscreen)
+ return uxa_screen->info->PixmapIsOffscreen(p);
+
+ return FALSE;
+}
+
+/**
+ * uxa_drawable_is_offscreen() is a convenience wrapper for uxa_pixmap_is_offscreen().
+ */
+Bool
+uxa_drawable_is_offscreen (DrawablePtr pDrawable)
+{
+ return uxa_pixmap_is_offscreen (uxa_get_drawable_pixmap (pDrawable));
+}
+
+/**
+ * Returns the pixmap which backs a drawable, and the offsets to add to
+ * coordinates to make them address the same bits in the backing drawable.
+ */
+PixmapPtr
+uxa_get_offscreen_pixmap (DrawablePtr drawable, int *xp, int *yp)
+{
+ PixmapPtr pixmap = uxa_get_drawable_pixmap (drawable);
+
+ uxa_get_drawable_deltas (drawable, pixmap, xp, yp);
+
+ if (uxa_pixmap_is_offscreen (pixmap))
+ return pixmap;
+ else
+ return NULL;
+}
+
+
+
+/**
+ * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler.
+ *
+ * It deals with waiting for synchronization with the card, determining if
+ * PrepareAccess() is necessary, and working around PrepareAccess() failure.
+ */
+void
+uxa_prepare_access(DrawablePtr pDrawable, int index)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+ Bool offscreen = uxa_pixmap_is_offscreen(pPixmap);
+
+ if (!offscreen)
+ return;
+
+ /* XXX should be pPixmap eventually */
+ uxa_wait_sync (pScreen);
+
+ if (uxa_screen->info->PrepareAccess)
+ (*uxa_screen->info->PrepareAccess) (pPixmap, index);
+}
+
+/**
+ * uxa_finish_access() is UXA's wrapper for the driver's FinishAccess() handler.
+ *
+ * It deals with calling the driver's FinishAccess() only if necessary.
+ */
+void
+uxa_finish_access(DrawablePtr pDrawable, int index)
+{
+ ScreenPtr pScreen = pDrawable->pScreen;
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+ PixmapPtr pPixmap = uxa_get_drawable_pixmap (pDrawable);
+
+ if (uxa_screen->info->FinishAccess == NULL)
+ return;
+
+ if (!uxa_pixmap_is_offscreen (pPixmap))
+ return;
+
+ (*uxa_screen->info->FinishAccess) (pPixmap, index);
+}
+
+/**
+ * uxa_validate_gc() sets the ops to UXA's implementations, which may be
+ * accelerated or may sync the card and fall back to fb.
+ */
+static void
+uxa_validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+ /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
+ * Preempt fbValidateGC by doing its work and masking the change out, so
+ * that we can do the Prepare/FinishAccess.
+ */
+#ifdef FB_24_32BIT
+ if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
+ (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
+ fbGetRotatedPixmap(pGC) = 0;
+ }
+
+ if (pGC->fillStyle == FillTiled) {
+ PixmapPtr pOldTile, pNewTile;
+
+ pOldTile = pGC->tile.pixmap;
+ if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ {
+ pNewTile = fbGetRotatedPixmap(pGC);
+ if (!pNewTile ||
+ pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
+ {
+ if (pNewTile)
+ (*pGC->pScreen->DestroyPixmap) (pNewTile);
+ /* fb24_32ReformatTile will do direct access of a newly-
+ * allocated pixmap. This isn't a problem yet, since we don't
+ * put pixmaps in FB until at least one accelerated UXA op.
+ */
+ uxa_prepare_access(&pOldTile->drawable, UXA_PREPARE_SRC);
+ pNewTile = fb24_32ReformatTile (pOldTile,
+ pDrawable->bitsPerPixel);
+ uxa_finish_access(&pOldTile->drawable, UXA_PREPARE_SRC);
+ }
+ if (pNewTile)
+ {
+ fbGetRotatedPixmap(pGC) = pOldTile;
+ pGC->tile.pixmap = pNewTile;
+ changes |= GCTile;
+ }
+ }
+ }
+#endif
+ if (changes & GCTile) {
+ if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width *
+ pDrawable->bitsPerPixel))
+ {
+ uxa_prepare_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+ fbPadPixmap (pGC->tile.pixmap);
+ uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_PREPARE_SRC);
+ }
+ /* Mask out the GCTile change notification, now that we've done FB's
+ * job for it.
+ */
+ changes &= ~GCTile;
+ }
+
+ uxa_prepare_access_gc(pGC);
+ fbValidateGC (pGC, changes, pDrawable);
+ uxa_finish_access_gc(pGC);
+
+ pGC->ops = (GCOps *) &uxa_ops;
+}
+
+static GCFuncs uxaGCFuncs = {
+ uxa_validate_gc,
+ miChangeGC,
+ miCopyGC,
+ miDestroyGC,
+ miChangeClip,
+ miDestroyClip,
+ miCopyClip
+};
+
+/**
+ * uxa_create_gc makes a new GC and hooks up its funcs handler, so that
+ * uxa_validate_gc() will get called.
+ */
+static int
+uxa_create_gc (GCPtr pGC)
+{
+ if (!fbCreateGC (pGC))
+ return FALSE;
+
+ pGC->funcs = &uxaGCFuncs;
+
+ return TRUE;
+}
+
+void
+uxa_prepare_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_prepare_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_prepare_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+void
+uxa_finish_access_window(WindowPtr pWin)
+{
+ if (pWin->backgroundState == BackgroundPixmap)
+ uxa_finish_access(&pWin->background.pixmap->drawable, UXA_PREPARE_SRC);
+
+ if (pWin->borderIsPixel == FALSE)
+ uxa_finish_access(&pWin->border.pixmap->drawable, UXA_PREPARE_SRC);
+}
+
+static Bool
+uxa_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+ Bool ret;
+
+ uxa_prepare_access_window(pWin);
+ ret = fbChangeWindowAttributes(pWin, mask);
+ uxa_finish_access_window(pWin);
+ return ret;
+}
+
+static RegionPtr
+uxa_bitmap_to_region(PixmapPtr pPix)
+{
+ RegionPtr ret;
+ uxa_prepare_access(&pPix->drawable, UXA_PREPARE_SRC);
+ ret = fbPixmapToRegion(pPix);
+ uxa_finish_access(&pPix->drawable, UXA_PREPARE_SRC);
+ return ret;
+}
+
+/**
+ * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's
+ * screen private, before calling down to the next CloseSccreen.
+ */
+static Bool
+uxa_close_screen(int i, ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+#ifdef RENDER
+ PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+
+ uxa_glyphs_fini(pScreen);
+
+ pScreen->CreateGC = uxa_screen->SavedCreateGC;
+ pScreen->CloseScreen = uxa_screen->SavedCloseScreen;
+ pScreen->GetImage = uxa_screen->SavedGetImage;
+ pScreen->GetSpans = uxa_screen->SavedGetSpans;
+ pScreen->CreatePixmap = uxa_screen->SavedCreatePixmap;
+ pScreen->DestroyPixmap = uxa_screen->SavedDestroyPixmap;
+ pScreen->CopyWindow = uxa_screen->SavedCopyWindow;
+ pScreen->ChangeWindowAttributes = uxa_screen->SavedChangeWindowAttributes;
+ pScreen->BitmapToRegion = uxa_screen->SavedBitmapToRegion;
+#ifdef RENDER
+ if (ps) {
+ ps->Composite = uxa_screen->SavedComposite;
+ ps->Glyphs = uxa_screen->SavedGlyphs;
+ ps->Trapezoids = uxa_screen->SavedTrapezoids;
+ ps->AddTraps = uxa_screen->SavedAddTraps;
+ ps->Triangles = uxa_screen->SavedTriangles;
+ }
+#endif
+
+ xfree (uxa_screen);
+
+ return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+/**
+ * This function allocates a driver structure for UXA drivers to fill in. By
+ * having UXA allocate the structure, the driver structure can be extended
+ * without breaking ABI between UXA and the drivers. The driver's
+ * responsibility is to check beforehand that the UXA module has a matching
+ * major number and sufficient minor. Drivers are responsible for freeing the
+ * driver structure using xfree().
+ *
+ * @return a newly allocated, zero-filled driver structure
+ */
+uxa_driver_t *
+uxa_driver_alloc(void)
+{
+ return xcalloc(1, sizeof(uxa_driver_t));
+}
+
+/**
+ * @param pScreen screen being initialized
+ * @param pScreenInfo UXA driver record
+ *
+ * uxa_driver_init sets up UXA given a driver record filled in by the driver.
+ * pScreenInfo should have been allocated by uxa_driver_alloc(). See the
+ * comments in _UxaDriver for what must be filled in and what is optional.
+ *
+ * @return TRUE if UXA was successfully initialized.
+ */
+Bool
+uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver)
+{
+ uxa_screen_t *uxa_screen;
+#ifdef RENDER
+ PictureScreenPtr ps;
+#endif
+
+ if (!uxa_driver)
+ return FALSE;
+
+ if (uxa_driver->uxa_major != UXA_VERSION_MAJOR ||
+ uxa_driver->uxa_minor > UXA_VERSION_MINOR)
+ {
+ LogMessage(X_ERROR, "UXA(%d): driver's UXA version requirements "
+ "(%d.%d) are incompatible with UXA version (%d.%d)\n",
+ screen->myNum,
+ uxa_driver->uxa_major, uxa_driver->uxa_minor,
+ UXA_VERSION_MAJOR, UXA_VERSION_MINOR);
+ return FALSE;
+ }
+
+ if (!uxa_driver->PrepareSolid) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareSolid must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->PrepareCopy) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::PrepareCopy must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ if (!uxa_driver->WaitMarker) {
+ LogMessage(X_ERROR, "UXA(%d): uxa_driver_t::WaitMarker must be "
+ "non-NULL\n", screen->myNum);
+ return FALSE;
+ }
+
+ /* If the driver doesn't set any max pitch values, we'll just assume
+ * that there's a limitation by pixels, and that it's the same as
+ * maxX.
+ *
+ * We want maxPitchPixels or maxPitchBytes to be set so we can check
+ * pixmaps against the max pitch in uxaCreatePixmap() -- it matters
+ * whether a pixmap is rejected because of its pitch or
+ * because of its width.
+ */
+ if (!uxa_driver->maxPitchPixels && !uxa_driver->maxPitchBytes)
+ {
+ uxa_driver->maxPitchPixels = uxa_driver->maxX;
+ }
+
+#ifdef RENDER
+ ps = GetPictureScreenIfSet(screen);
+#endif
+
+ uxa_screen = xcalloc (sizeof (uxa_screen_t), 1);
+
+ if (!uxa_screen) {
+ LogMessage(X_WARNING, "UXA(%d): Failed to allocate screen private\n",
+ screen->myNum);
+ return FALSE;
+ }
+
+ uxa_screen->info = uxa_driver;
+
+ dixSetPrivate(&screen->devPrivates, uxa_screen_key, uxa_screen);
+
+// exaDDXDriverInit(screen);
+
+ /*
+ * Replace various fb screen functions
+ */
+ uxa_screen->SavedCloseScreen = screen->CloseScreen;
+ screen->CloseScreen = uxa_close_screen;
+
+ uxa_screen->SavedCreateGC = screen->CreateGC;
+ screen->CreateGC = uxa_create_gc;
+
+ uxa_screen->SavedGetImage = screen->GetImage;
+ screen->GetImage = uxa_get_image;
+
+ uxa_screen->SavedGetSpans = screen->GetSpans;
+ screen->GetSpans = uxa_check_get_spans;
+
+ uxa_screen->SavedCopyWindow = screen->CopyWindow;
+ screen->CopyWindow = uxa_copy_window;
+
+ uxa_screen->SavedChangeWindowAttributes = screen->ChangeWindowAttributes;
+ screen->ChangeWindowAttributes = uxa_change_window_attributes;
+
+ uxa_screen->SavedBitmapToRegion = screen->BitmapToRegion;
+ screen->BitmapToRegion = uxa_bitmap_to_region;
+
+#ifdef RENDER
+ if (ps) {
+ uxa_screen->SavedComposite = ps->Composite;
+ ps->Composite = uxa_composite;
+
+ uxa_screen->SavedGlyphs = ps->Glyphs;
+ ps->Glyphs = uxa_glyphs;
+
+ uxa_screen->SavedTriangles = ps->Triangles;
+ ps->Triangles = uxa_triangles;
+
+ uxa_screen->SavedTrapezoids = ps->Trapezoids;
+ ps->Trapezoids = uxa_trapezoids;
+
+ uxa_screen->SavedAddTraps = ps->AddTraps;
+ ps->AddTraps = uxa_check_add_traps;
+ }
+#endif
+
+#ifdef MITSHM
+ /* Re-register with the MI funcs, which don't allow shared pixmaps.
+ * Shared pixmaps are almost always a performance loss for us, but this
+ * still allows for SHM PutImage.
+ */
+ ShmRegisterFuncs(screen, &uxa_shm_funcs);
+#endif
+
+ uxa_glyphs_init(screen);
+
+ LogMessage(X_INFO, "UXA(%d): Driver registered support for the following"
+ " operations:\n", screen->myNum);
+ assert(uxa_driver->PrepareSolid != NULL);
+ LogMessage(X_INFO, " Solid\n");
+ assert(uxa_driver->PrepareCopy != NULL);
+ LogMessage(X_INFO, " Copy\n");
+ if (uxa_driver->PrepareComposite != NULL) {
+ LogMessage(X_INFO, " Composite (RENDER acceleration)\n");
+ }
+ if (uxa_driver->UploadToScreen != NULL) {
+ LogMessage(X_INFO, " UploadToScreen\n");
+ }
+ if (uxa_driver->DownloadFromScreen != NULL) {
+ LogMessage(X_INFO, " DownloadFromScreen\n");
+ }
+
+ return TRUE;
+}
+
+/**
+ * uxa_driver_fini tears down UXA on a given screen.
+ *
+ * @param pScreen screen being torn down.
+ */
+void
+uxa_driver_fini (ScreenPtr pScreen)
+{
+ /*right now does nothing*/
+}
+
+/**
+ * uxa_mark_sync() should be called after any asynchronous drawing by the hardware.
+ *
+ * @param pScreen screen which drawing occurred on
+ *
+ * uxa_mark_sync() sets a flag to indicate that some asynchronous drawing has
+ * happened and a WaitSync() will be necessary before relying on the contents of
+ * offscreen memory from the CPU's perspective. It also calls an optional
+ * driver MarkSync() callback, the return value of which may be used to do partial
+ * synchronization with the hardware in the future.
+ */
+void uxa_mark_sync(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ uxa_screen->info->needsSync = TRUE;
+ if (uxa_screen->info->MarkSync != NULL) {
+ uxa_screen->info->lastMarker = (*uxa_screen->info->MarkSync)(pScreen);
+ }
+}
+
+/**
+ * uxa_wait_sync() ensures that all drawing has been completed.
+ *
+ * @param pScreen screen being synchronized.
+ *
+ * Calls down into the driver to ensure that all previous drawing has completed.
+ * It should always be called before relying on the framebuffer contents
+ * reflecting previous drawing, from a CPU perspective.
+ */
+void uxa_wait_sync(ScreenPtr pScreen)
+{
+ uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
+
+ if (uxa_screen->info->needsSync && !uxa_screen->swappedOut) {
+ (*uxa_screen->info->WaitMarker)(pScreen, uxa_screen->info->lastMarker);
+ uxa_screen->info->needsSync = FALSE;
+ }
+}
diff --git a/uxa/uxa.h b/uxa/uxa.h
new file mode 100644
index 00000000..57e84f37
--- /dev/null
+++ b/uxa/uxa.h
@@ -0,0 +1,671 @@
+/*
+ * Copyright © 2000, 2008 Keith Packard
+ * 2004 Eric Anholt
+ * 2005 Zack Rusin
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Copyright holders make no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/** @file
+ * UXA - the unified memory acceleration architecture.
+ *
+ * This is the header containing the public API of UXA for uxa drivers.
+ */
+
+#ifndef UXA_H
+#define UXA_H
+
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "gcstruct.h"
+#include "picturestr.h"
+#include "fb.h"
+
+#define UXA_VERSION_MAJOR 1
+#define UXA_VERSION_MINOR 0
+#define UXA_VERSION_RELEASE 0
+
+/**
+ * The UxaDriver structure is allocated through uxa_driver_alloc(), and then
+ * fllled in by drivers.
+ */
+typedef struct _UxaDriver {
+ /**
+ * uxa_major and uxa_minor should be set by the driver to the version of
+ * UXA which the driver was compiled for (or configures itself at runtime
+ * to support). This allows UXA to extend the structure for new features
+ * without breaking ABI for drivers compiled against older versions.
+ */
+ int uxa_major, uxa_minor;
+
+ /**
+ * The flags field is bitfield of boolean values controlling UXA's behavior.
+ *
+ * The flags include UXA_TWO_BITBLT_DIRECTIONS.
+ */
+ int flags;
+
+ /** @{ */
+ /**
+ * maxX controls the X coordinate limitation for rendering from the card.
+ * The driver should never receive a request for rendering beyond maxX
+ * in the X direction from the origin of a pixmap.
+ */
+ int maxX;
+
+ /**
+ * maxY controls the Y coordinate limitation for rendering from the card.
+ * The driver should never receive a request for rendering beyond maxY
+ * in the Y direction from the origin of a pixmap.
+ */
+ int maxY;
+ /** @} */
+
+ /* private */
+ Bool needsSync;
+ int lastMarker;
+
+ /** @name Solid
+ * @{
+ */
+ /**
+ * PrepareSolid() sets up the driver for doing a solid fill.
+ * @param pPixmap Destination pixmap
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ * @param fg "foreground" color for the fill
+ *
+ * This call should set up the driver for doing a series of solid fills
+ * through the Solid() call. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls
+ * which bits of the destination should be affected, and will only represent
+ * the bits up to the depth of pPixmap. The fg is the pixel value of the
+ * foreground color referred to in ROP descriptions.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareSolid() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*PrepareSolid) (PixmapPtr pPixmap,
+ int alu,
+ Pixel planemask,
+ Pixel fg);
+
+ /**
+ * Solid() performs a solid fill set up in the last PrepareSolid() call.
+ *
+ * @param pPixmap destination pixmap
+ * @param x1 left coordinate
+ * @param y1 top coordinate
+ * @param x2 right coordinate
+ * @param y2 bottom coordinate
+ *
+ * Performs the fill set up by the last PrepareSolid() call, covering the
+ * area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
+ * in the coordinate space of the destination pixmap, so the driver will
+ * need to set up the hardware's offset and pitch for the destination
+ * coordinates according to the pixmap's offset and pitch within
+ * framebuffer.
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+ void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
+
+ /**
+ * DoneSolid() finishes a set of solid fills.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneSolid() call is called at the end of a series of consecutive
+ * Solid() calls following a successful PrepareSolid(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareSolid().
+ *
+ * This call is required if PrepareSolid() ever succeeds.
+ */
+ void (*DoneSolid) (PixmapPtr pPixmap);
+ /** @} */
+
+ /** @name Copy
+ * @{
+ */
+ /**
+ * PrepareCopy() sets up the driver for doing a copy within video
+ * memory.
+ *
+ * @param pSrcPixmap source pixmap
+ * @param pDstPixmap destination pixmap
+ * @param dx X copy direction
+ * @param dy Y copy direction
+ * @param alu raster operation
+ * @param planemask write mask for the fill
+ *
+ * This call should set up the driver for doing a series of copies from the
+ * the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
+ * hardware should do the copy from the left to the right, and dy will be
+ * positive if the copy should be done from the top to the bottom. This
+ * is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
+ * If your hardware can only support blits that are (left to right, top to
+ * bottom) or (right to left, bottom to top), then you should set
+ * #UXA_TWO_BITBLT_DIRECTIONS, and UXA will break down Copy operations to
+ * ones that meet those requirements. The alu raster op is one of the GX*
+ * graphics functions listed in X.h, and typically maps to a similar
+ * single-byte "ROP" setting in all hardware. The planemask controls which
+ * bits of the destination should be affected, and will only represent the
+ * bits up to the depth of pPixmap.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareCopy() call is required of all drivers, but it may fail for any
+ * reason. Failure results in a fallback to software rendering.
+ */
+ Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ int dx,
+ int dy,
+ int alu,
+ Pixel planemask);
+
+ /**
+ * Copy() performs a copy set up in the last PrepareCopy call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied.
+ *
+ * Performs the copy set up by the last PrepareCopy() call, copying the
+ * rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
+ * pixmap to the same-sized rectangle at (dstX, dstY) in the destination
+ * pixmap. Those rectangles may overlap in memory, if
+ * pSrcPixmap == pDstPixmap. Note that this call does not receive the
+ * pSrcPixmap as an argument -- if it's needed in this function, it should
+ * be stored in the driver private during PrepareCopy(). As with Solid(),
+ * the coordinates are in the coordinate space of each pixmap, so the driver
+ * will need to set up source and destination pitches and offsets from those
+ * pixmaps, probably using uxaGetPixmapOffset() and uxa_get_pixmap_pitch().
+ *
+ * This call is required if PrepareCopy ever succeeds.
+ */
+ void (*Copy) (PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * DoneCopy() finishes a set of copies.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneCopy() call is called at the end of a series of consecutive
+ * Copy() calls following a successful PrepareCopy(). This allows drivers
+ * to finish up emitting drawing commands that were buffered, or clean up
+ * state from PrepareCopy().
+ *
+ * This call is required if PrepareCopy() ever succeeds.
+ */
+ void (*DoneCopy) (PixmapPtr pDstPixmap);
+ /** @} */
+
+ /** @name Composite
+ * @{
+ */
+ /**
+ * CheckComposite() checks to see if a composite operation could be
+ * accelerated.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ *
+ * The CheckComposite() call checks if the driver could handle acceleration
+ * of op with the given source, mask, and destination pictures. This allows
+ * drivers to check source and destination formats, supported operations,
+ * transformations, and component alpha state, and send operations it can't
+ * support to software rendering early on. This avoids costly pixmap
+ * migration to the wrong places when the driver can't accelerate
+ * operations. Note that because migration hasn't happened, the driver
+ * can't know during CheckComposite() what the offsets and pitches of the
+ * pixmaps are going to be.
+ *
+ * See PrepareComposite() for more details on likely issues that drivers
+ * will have in accelerating Composite operations.
+ *
+ * The CheckComposite() call is recommended if PrepareComposite() is
+ * implemented, but is not required.
+ */
+ Bool (*CheckComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture);
+
+ /**
+ * PrepareComposite() sets up the driver for doing a Composite operation
+ * described in the Render extension protocol spec.
+ *
+ * @param op Render operation
+ * @param pSrcPicture source Picture
+ * @param pMaskPicture mask picture
+ * @param pDstPicture destination Picture
+ * @param pSrc source pixmap
+ * @param pMask mask pixmap
+ * @param pDst destination pixmap
+ *
+ * This call should set up the driver for doing a series of Composite
+ * operations, as described in the Render protocol spec, with the given
+ * pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
+ * pDst are the pixmaps containing the pixel data, and should be used for
+ * setting the offset and pitch used for the coordinate spaces for each of
+ * the Pictures.
+ *
+ * Notes on interpreting Picture structures:
+ * - The Picture structures will always have a valid pDrawable.
+ * - The Picture structures will never have alphaMap set.
+ * - The mask Picture (and therefore pMask) may be NULL, in which case the
+ * operation is simply src OP dst instead of src IN mask OP dst, and
+ * mask coordinates should be ignored.
+ * - pMarkPicture may have componentAlpha set, which greatly changes
+ * the behavior of the Composite operation. componentAlpha has no effect
+ * when set on pSrcPicture or pDstPicture.
+ * - The source and mask Pictures may have a transformation set
+ * (Picture->transform != NULL), which means that the source coordinates
+ * should be transformed by that transformation, resulting in scaling,
+ * rotation, etc. The PictureTransformPoint() call can transform
+ * coordinates for you. Transforms have no effect on Pictures when used
+ * as a destination.
+ * - The source and mask pictures may have a filter set. PictFilterNearest
+ * and PictFilterBilinear are defined in the Render protocol, but others
+ * may be encountered, and must be handled correctly (usually by
+ * PrepareComposite failing, and falling back to software). Filters have
+ * no effect on Pictures when used as a destination.
+ * - The source and mask Pictures may have repeating set, which must be
+ * respected. Many chipsets will be unable to support repeating on
+ * pixmaps that have a width or height that is not a power of two.
+ *
+ * If your hardware can't support source pictures (textures) with
+ * non-power-of-two pitches, you should set #UXA_OFFSCREEN_ALIGN_POT.
+ *
+ * Note that many drivers will need to store some of the data in the driver
+ * private record, for sending to the hardware with each drawing command.
+ *
+ * The PrepareComposite() call is not required. However, it is highly
+ * recommended for performance of antialiased font rendering and performance
+ * of cairo applications. Failure results in a fallback to software
+ * rendering.
+ */
+ Bool (*PrepareComposite) (int op,
+ PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture,
+ PicturePtr pDstPicture,
+ PixmapPtr pSrc,
+ PixmapPtr pMask,
+ PixmapPtr pDst);
+
+ /**
+ * Composite() performs a Composite operation set up in the last
+ * PrepareComposite() call.
+ *
+ * @param pDstPixmap destination pixmap
+ * @param srcX source X coordinate
+ * @param srcY source Y coordinate
+ * @param maskX source X coordinate
+ * @param maskY source Y coordinate
+ * @param dstX destination X coordinate
+ * @param dstY destination Y coordinate
+ * @param width destination rectangle width
+ * @param height destination rectangle height
+ *
+ * Performs the Composite operation set up by the last PrepareComposite()
+ * call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
+ * in the destination Pixmap. Note that if a transformation was set on
+ * the source or mask Pictures, the source rectangles may not be the same
+ * size as the destination rectangles and filtering. Getting the coordinate
+ * transformation right at the subpixel level can be tricky, and rendercheck
+ * can test this for you.
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+ void (*Composite) (PixmapPtr pDst,
+ int srcX,
+ int srcY,
+ int maskX,
+ int maskY,
+ int dstX,
+ int dstY,
+ int width,
+ int height);
+
+ /**
+ * DoneComposite() finishes a set of Composite operations.
+ *
+ * @param pPixmap destination pixmap.
+ *
+ * The DoneComposite() call is called at the end of a series of consecutive
+ * Composite() calls following a successful PrepareComposite(). This allows
+ * drivers to finish up emitting drawing commands that were buffered, or
+ * clean up state from PrepareComposite().
+ *
+ * This call is required if PrepareComposite() ever succeeds.
+ */
+ void (*DoneComposite) (PixmapPtr pDst);
+ /** @} */
+
+ /**
+ * UploadToScreen() loads a rectangle of data from src into pDst.
+ *
+ * @param pDst destination pixmap
+ * @param x destination X coordinate.
+ * @param y destination Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied
+ * @param src pointer to the beginning of the source data
+ * @param src_pitch pitch (in bytes) of the lines of source data.
+ *
+ * UploadToScreen() copies data in system memory beginning at src (with
+ * pitch src_pitch) into the destination pixmap from (x, y) to
+ * (x + width, y + height). This is typically done with hostdata uploads,
+ * where the CPU sets up a blit command on the hardware with instructions
+ * that the blit data will be fed through some sort of aperture on the card.
+ *
+ * If UploadToScreen() is performed asynchronously, it is up to the driver
+ * to call uxa_mark_sync(). This is in contrast to most other acceleration
+ * calls in UXA.
+ *
+ * UploadToScreen() can aid in pixmap migration, but is most important for
+ * the performance of uxa_glyphs() (antialiased font drawing) by allowing
+ * pipelining of data uploads, avoiding a sync of the card after each glyph.
+ *
+ * @return TRUE if the driver successfully uploaded the data. FALSE
+ * indicates that UXA should fall back to doing the upload in software.
+ *
+ * UploadToScreen() is not required, but is recommended if Composite
+ * acceleration is supported.
+ */
+ Bool (*UploadToScreen) (PixmapPtr pDst,
+ int x,
+ int y,
+ int w,
+ int h,
+ char *src,
+ int src_pitch);
+
+ /**
+ * UploadToScratch() is used to upload a pixmap to a scratch area for
+ * acceleration.
+ *
+ * @param pSrc source pixmap in host memory
+ * @param pDst fake, scratch pixmap to be set up in offscreen memory.
+ *
+ * The UploadToScratch() call was added to support Xati before Xati had
+ * support for hostdata uploads and before uxa_glyphs() was written. It
+ * behaves incorrectly (uses an invalid pixmap as pDst),
+ * and UploadToScreen() should be implemented instead.
+ *
+ * Drivers implementing UploadToScratch() had to set up space (likely in a
+ * statically allocated area) in offscreen memory, copy pSrc to that
+ * scratch area, and adust pDst->devKind for the pitch and
+ * pDst->devPrivate.ptr for the pointer to that scratch area. The driver
+ * was responsible for syncing (as it was implemented using memcpy() in
+ * Xati), and only the data from the last UploadToScratch() was guaranteed
+ * to be valid at any given time.
+ *
+ * UploadToScratch() should not be implemented by drivers, and will likely
+ * be removed in a future version of UXA.
+ */
+ Bool (*UploadToScratch) (PixmapPtr pSrc,
+ PixmapPtr pDst);
+
+ /**
+ * DownloadFromScreen() loads a rectangle of data from pSrc into dst
+ *
+ * @param pSrc source pixmap
+ * @param x source X coordinate.
+ * @param y source Y coordinate
+ * @param width width of the rectangle to be copied
+ * @param height height of the rectangle to be copied
+ * @param dst pointer to the beginning of the destination data
+ * @param dst_pitch pitch (in bytes) of the lines of destination data.
+ *
+ * DownloadFromScreen() copies data from offscreen memory in pSrc from
+ * (x, y) to (x + width, y + height), to system memory starting at
+ * dst (with pitch dst_pitch). This would usually be done
+ * using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
+ * and then synchronously reading from AGP. Because the implementation
+ * might be synchronous, UXA leaves it up to the driver to call
+ * uxa_mark_sync() if DownloadFromScreen() was asynchronous. This is in
+ * contrast to most other acceleration calls in UXA.
+ *
+ * DownloadFromScreen() can aid in the largest bottleneck in pixmap
+ * migration, which is the read from framebuffer when evicting pixmaps from
+ * framebuffer memory. Thus, it is highly recommended, even though
+ * implementations are typically complicated.
+ *
+ * @return TRUE if the driver successfully downloaded the data. FALSE
+ * indicates that UXA should fall back to doing the download in software.
+ *
+ * DownloadFromScreen() is not required, but is highly recommended.
+ */
+ Bool (*DownloadFromScreen)(PixmapPtr pSrc,
+ int x, int y,
+ int w, int h,
+ char *dst, int dst_pitch);
+
+ /**
+ * MarkSync() requests that the driver mark a synchronization point,
+ * returning an driver-defined integer marker which could be requested for
+ * synchronization to later in WaitMarker(). This might be used in the
+ * future to avoid waiting for full hardware stalls before accessing pixmap
+ * data with the CPU, but is not important in the current incarnation of
+ * UXA.
+ *
+ * Note that drivers should call uxa_mark_sync() when they have done some
+ * acceleration, rather than their own MarkSync() handler, as otherwise UXA
+ * will be unaware of the driver's acceleration and not sync to it during
+ * fallbacks.
+ *
+ * MarkSync() is optional.
+ */
+ int (*MarkSync) (ScreenPtr pScreen);
+
+ /**
+ * WaitMarker() waits for all rendering before the given marker to have
+ * completed. If the driver does not implement MarkSync(), marker is
+ * meaningless, and all rendering by the hardware should be completed before
+ * WaitMarker() returns.
+ *
+ * Note that drivers should call uxa_wait_sync() to wait for all acceleration
+ * to finish, as otherwise UXA will be unaware of the driver having
+ * synchronized, resulting in excessive WaitMarker() calls.
+ *
+ * WaitMarker() is required of all drivers.
+ */
+ void (*WaitMarker) (ScreenPtr pScreen, int marker);
+
+ /** @{ */
+ /**
+ * PrepareAccess() is called before CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * PrepareAccess() will be called before CPU access to an offscreen pixmap.
+ * This can be used to set up hardware surfaces for byteswapping or
+ * untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
+ * making CPU access use a different aperture.
+ *
+ * The index is one of #UXA_PREPARE_DEST, #UXA_PREPARE_SRC, or
+ * #UXA_PREPARE_MASK, indicating which pixmap is in question. Since only up
+ * to three pixmaps will have PrepareAccess() called on them per operation,
+ * drivers can have a small, statically-allocated space to maintain state
+ * for PrepareAccess() and FinishAccess() in. Note that the same pixmap may
+ * have PrepareAccess() called on it more than once, for uxample when doing
+ * a copy within the same pixmap (so it gets PrepareAccess as()
+ * #UXA_PREPARE_DEST and then as #UXA_PREPARE_SRC).
+ *
+ * PrepareAccess() may fail. An uxample might be the case of hardware that
+ * can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
+ * fails, UXA will migrate the pixmap to system memory.
+ * DownloadFromScreen() must be implemented and must not fail if a driver
+ * wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
+ * pPix is the visible screen, because the visible screen can not be
+ * migrated.
+ *
+ * @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
+ * drawing.
+ * @return FALSE if PrepareAccess() is unsuccessful and UXA should use
+ * DownloadFromScreen() to migate the pixmap out.
+ */
+ Bool (*PrepareAccess)(PixmapPtr pPix, int index);
+
+ /**
+ * FinishAccess() is called after CPU access to an offscreen pixmap.
+ *
+ * @param pPix the pixmap being accessed
+ * @param index the index of the pixmap being accessed.
+ *
+ * FinishAccess() will be called after finishing CPU access of an offscreen
+ * pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
+ * called if PrepareAccess() failed and the pixmap was migrated out.
+ */
+ void (*FinishAccess)(PixmapPtr pPix, int index);
+
+ /**
+ * PixmapIsOffscreen() is an optional driver replacement to
+ * uxa_pixmap_is_offscreen(). Set to NULL if you want the standard behaviour
+ * of uxa_pixmap_is_offscreen().
+ *
+ * @param pPix the pixmap
+ * @return TRUE if the given drawable is in framebuffer memory.
+ *
+ * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen
+ * memory, meaning that acceleration could probably be done to it, and that it
+ * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
+ * with the CPU.
+ *
+ *
+ */
+ Bool (*PixmapIsOffscreen)(PixmapPtr pPix);
+
+ /** @name PrepareAccess() and FinishAccess() indices
+ * @{
+ */
+ /**
+ * UXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
+ * read from.
+ */
+ #define UXA_PREPARE_DEST 0
+ /**
+ * UXA_PREPARE_SRC is the index for a pixmap that may be read from
+ */
+ #define UXA_PREPARE_SRC 1
+ /**
+ * UXA_PREPARE_SRC is the index for a second pixmap that may be read
+ * from.
+ */
+ #define UXA_PREPARE_MASK 2
+ /** @} */
+
+ /**
+ * maxPitchPixels controls the pitch limitation for rendering from
+ * the card.
+ * The driver should never receive a request for rendering a pixmap
+ * that has a pitch (in pixels) beyond maxPitchPixels.
+ *
+ * Setting this field is optional -- if your hardware doesn't have
+ * a pitch limitation in pixels, don't set this. If neither this value
+ * nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
+ * If set, it must not be smaller than maxX.
+ *
+ * @sa maxPitchBytes
+ */
+ int maxPitchPixels;
+
+ /**
+ * maxPitchBytes controls the pitch limitation for rendering from
+ * the card.
+ * The driver should never receive a request for rendering a pixmap
+ * that has a pitch (in bytes) beyond maxPitchBytes.
+ *
+ * Setting this field is optional -- if your hardware doesn't have
+ * a pitch limitation in bytes, don't set this.
+ * If set, it must not be smaller than maxX * 4.
+ * There's no default value for maxPitchBytes.
+ *
+ * @sa maxPitchPixels
+ */
+ int maxPitchBytes;
+
+ /** @} */
+} uxa_driver_t;
+
+/** @name UXA driver flags
+ * @{
+ */
+/**
+ * UXA_TWO_BITBLT_DIRECTIONS indicates to UXA that the driver can only
+ * support copies that are (left-to-right, top-to-bottom) or
+ * (right-to-left, bottom-to-top).
+ */
+#define UXA_TWO_BITBLT_DIRECTIONS (1 << 2)
+
+/** @} */
+
+uxa_driver_t *
+uxa_driver_alloc(void);
+
+Bool
+uxa_driver_init(ScreenPtr screen, uxa_driver_t *uxa_driver);
+
+void
+uxa_driver_fini(ScreenPtr pScreen);
+
+void
+uxa_mark_sync(ScreenPtr pScreen);
+
+void
+uxa_wait_sync(ScreenPtr pScreen);
+
+void
+uxaEnableDisableFBAccess (int index, Bool enable);
+
+CARD32
+uxa_get_pixmap_first_pixel (PixmapPtr pPixmap);
+
+/**
+ * Returns TRUE if the given planemask covers all the significant bits in the
+ * pixel values for pDrawable.
+ */
+#define UXA_PM_IS_SOLID(_pDrawable, _pm) \
+ (((_pm) & FbFullMask((_pDrawable)->depth)) == \
+ FbFullMask((_pDrawable)->depth))
+
+#endif /* UXA_H */