summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--exa/exa.h2
-rw-r--r--exa/exa_accel.c125
2 files changed, 126 insertions, 1 deletions
diff --git a/exa/exa.h b/exa/exa.h
index 54f07e53d..501f5e787 100644
--- a/exa/exa.h
+++ b/exa/exa.h
@@ -206,7 +206,7 @@ typedef struct _ExaDriver {
#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
-
+#define EXA_TWO_BITBLT_DIRECTIONS (1 << 2)
#define EXA_MAKE_VERSION(a, b, c) (((a) << 16) | ((b) << 8) | (c))
#define EXA_VERSION \
diff --git a/exa/exa_accel.c b/exa/exa_accel.c
index b7b8bd1b1..365e6313c 100644
--- a/exa/exa_accel.c
+++ b/exa/exa_accel.c
@@ -124,6 +124,123 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n,
exaMarkSync(pScreen);
}
+static Bool inline
+exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
+ GCPtr pGC, BoxPtr pbox, int nbox, int dx, int dy)
+{
+ ExaScreenPriv (pDstDrawable->pScreen);
+ PixmapPtr pSrcPixmap, pDstPixmap;
+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
+ int dirsetup;
+
+ /* Need to get both pixmaps to call the driver routines */
+ pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y);
+ pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y);
+ if (!pSrcPixmap || !pDstPixmap)
+ return FALSE;
+
+ /*
+ * Now the case of a chip that only supports xdir = ydir = 1 or
+ * xdir = ydir = -1, but we have xdir != ydir.
+ */
+ dirsetup = 0; /* No direction set up yet. */
+ for (; nbox; pbox++, nbox--) {
+ if (dx >= 0 && (src_off_y + pbox->y1 + dy) != pbox->y1) {
+ /* Do a xdir = ydir = -1 blit instead. */
+ if (dirsetup != -1) {
+ dirsetup = -1;
+ if (!(*pExaScr->info->accel.PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu :
+ GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*pExaScr->info->accel.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) {
+ dirsetup = 1;
+ if (!(*pExaScr->info->accel.PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu :
+ GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ (*pExaScr->info->accel.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) {
+ dirsetup = 1;
+ if (!(*pExaScr->info->accel.PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ 1, 1,
+ pGC ? pGC->alu :
+ GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--)
+ (*pExaScr->info->accel.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) {
+ dirsetup = -1;
+ if (!(*pExaScr->info->accel.PrepareCopy)(pSrcPixmap,
+ pDstPixmap,
+ -1, -1,
+ pGC ? pGC->alu :
+ GXcopy,
+ pGC ? pGC->planemask :
+ FB_ALLONES))
+ return FALSE;
+ }
+ for (i = 0; i < pbox->y2 - pbox->y1; i++)
+ (*pExaScr->info->accel.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);
+ }
+ }
+ (*pExaScr->info->accel.DoneCopy)(pDstPixmap);
+ exaMarkSync(pDstDrawable->pScreen);
+ exaDrawableDirty(pDstDrawable);
+ return TRUE;
+}
+
void
exaCopyNtoN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
@@ -169,6 +286,14 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
exaDrawableUseMemory (pDstDrawable);
}
+ /* Mixed directions must be handled specially if the card is lame */
+ if (pExaScr->info->card.flags & EXA_TWO_BITBLT_DIRECTIONS && (dx*dy) < 0) {
+ if (!exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
+ dx, dy))
+ goto fallback;
+ return;
+ }
+
if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) &&
(pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) &&
(*pExaScr->info->accel.PrepareCopy) (pSrcPixmap,