summaryrefslogtreecommitdiff
path: root/src/ffb_dbe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ffb_dbe.c')
-rw-r--r--src/ffb_dbe.c902
1 files changed, 902 insertions, 0 deletions
diff --git a/src/ffb_dbe.c b/src/ffb_dbe.c
new file mode 100644
index 0000000..09395f7
--- /dev/null
+++ b/src/ffb_dbe.c
@@ -0,0 +1,902 @@
+/*
+ * Acceleration for the Creator and Creator3D framebuffer - Dbe Acceleration.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sunffb/ffb_dbe.c,v 1.2 2003/02/11 03:19:02 dawes Exp $ */
+
+#define NEED_REPLIES
+#define NEED_EVENTS
+#include "X.h"
+#include "Xproto.h"
+#include "misc.h"
+#include "os.h"
+#include "windowstr.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "extnsionst.h"
+#include "dixstruct.h"
+#include "resource.h"
+#include "opaque.h"
+#include "dbestruct.h"
+#include "regionstr.h"
+#include "gcstruct.h"
+#include "inputstr.h"
+
+#define PSZ 8
+#include "cfb.h"
+#undef PSZ
+#include "cfb32.h"
+
+#include "xf86_ansic.h"
+#include "xf86.h"
+
+#include "ffb.h"
+#include "ffb_fifo.h"
+#include "ffb_rcache.h"
+
+static int FFBDbePrivPrivGeneration = 0;
+static int FFBDbeWindowPrivPrivIndex = -1;
+static RESTYPE dbeDrawableResType;
+static RESTYPE dbeWindowPrivResType;
+static int dbeScreenPrivIndex = -1;
+static int dbeWindowPrivIndex = -1;
+
+#define FFB_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv) \
+ (((FFBDbeWindowPrivPrivIndex < 0) || (!pDbeWindowPriv)) ? \
+ NULL : \
+ ((FFBDbeWindowPrivPrivPtr) \
+ ((pDbeWindowPriv)->devPrivates[FFBDbeWindowPrivPrivIndex].ptr)))
+
+#define FFB_DBE_WINDOW_PRIV_PRIV_FROM_WINDOW(pWin) \
+ FFB_DBE_WINDOW_PRIV_PRIV(DBE_WINDOW_PRIV(pWin))
+
+typedef struct _FFBDbeWindowPrivPrivRec {
+ int HwAccelerated;
+ int HwCurrentBuf; /* 0 = buffer A, 1 = buffer B */
+
+ /* We need also what midbe would use in case we must
+ * revert to unaccelerated dbe.
+ */
+ PixmapPtr pBackBuffer;
+ PixmapPtr pFrontBuffer;
+
+ /* Back pointer to generic DBE layer window private. */
+ DbeWindowPrivPtr pDbeWindowPriv;
+} FFBDbeWindowPrivPrivRec, *FFBDbeWindowPrivPrivPtr;
+
+static Bool
+FFBDbeGetVisualInfo(ScreenPtr pScreen, XdbeScreenVisualInfo *pScrVisInfo)
+{
+ XdbeVisualInfo *visInfo;
+ DepthPtr pDepth;
+ int i, j, k, count;
+
+ /* XXX Should check for double-buffer presence. But even if
+ * XXX the double-buffer is not present we can still play
+ * XXX tricks with GetWindowPixmap in 8bpp mode, ie. double
+ * XXX buffer between the R and G planes of buffer A. -DaveM
+ */
+
+ /* Determine number of visuals for this screen. */
+ for (i = 0, count = 0; i < pScreen->numDepths; i++)
+ count += pScreen->allowedDepths[i].numVids;
+
+ /* Allocate an array of XdbeVisualInfo items. */
+ if (!(visInfo = (XdbeVisualInfo *)xalloc(count * sizeof(XdbeVisualInfo))))
+ return FALSE;
+
+ for (i = 0, k = 0; i < pScreen->numDepths; i++) {
+ /* For each depth of this screen, get visual information. */
+ pDepth = &pScreen->allowedDepths[i];
+ for (j = 0; j < pDepth->numVids; j++) {
+ /* For each visual for this depth of this screen, get visual ID
+ * and visual depth. For now, we will always return
+ * the same performance level for all visuals (0). A higher
+ * performance level value indicates higher performance.
+ */
+ visInfo[k].visual = pDepth->vids[j];
+ visInfo[k].depth = pDepth->depth;
+
+ /* XXX We should set this appropriately... -DaveM */
+ visInfo[k].perflevel = 0;
+ k++;
+ }
+ }
+
+ /* Record the number of visuals and point visual_depth to
+ * the array of visual info.
+ */
+ pScrVisInfo->count = count;
+ pScrVisInfo->visinfo = visInfo;
+
+ return TRUE;
+}
+
+static void
+FFBDbeUpdateWidPlane(WindowPtr pWin, GCPtr pGC)
+{
+ FFBPtr pFfb = GET_FFB_FROM_SCREEN(pWin->drawable.pScreen);
+ CreatorPrivWinPtr pFfbPrivWin = CreatorGetWindowPrivate(pWin);
+ RegionPtr prgnClip;
+ BoxPtr pboxClipped, pboxClippedBase;
+ unsigned int fbc;
+ int numRects;
+ int x, y, w, h;
+
+ x = pWin->drawable.x;
+ y = pWin->drawable.y;
+ w = pWin->drawable.width;
+ h = pWin->drawable.height;
+
+ fbc = pFfbPrivWin->fbc_base;
+ fbc = (fbc & ~FFB_FBC_WB_MASK) | FFB_FBC_WB_AB;
+ fbc = (fbc & ~FFB_FBC_XE_MASK) | FFB_FBC_XE_ON;
+ fbc = (fbc & ~FFB_FBC_RGBE_MASK) | FFB_FBC_RGBE_OFF;
+
+ prgnClip = cfbGetCompositeClip(pGC);
+ numRects = REGION_NUM_RECTS (prgnClip);
+ pboxClippedBase = (BoxPtr) ALLOCATE_LOCAL(numRects * sizeof(BoxRec));
+ if (!pboxClippedBase)
+ return;
+
+ pboxClipped = pboxClippedBase;
+ {
+ int x1, y1, x2, y2, bx2, by2;
+ BoxRec box;
+ BoxPtr pextent;
+
+ pextent = REGION_EXTENTS(pGC->pScreen, prgnClip);
+ x1 = pextent->x1;
+ y1 = pextent->y1;
+ x2 = pextent->x2;
+ y2 = pextent->y2;
+
+ if ((box.x1 = x) < x1)
+ box.x1 = x1;
+
+ if ((box.y1 = y) < y1)
+ box.y1 = y1;
+
+ bx2 = (int) x + (int) w;
+ if (bx2 > x2)
+ bx2 = x2;
+ box.x2 = bx2;
+
+ by2 = (int) y + (int) h;
+ if (by2 > y2)
+ by2 = y2;
+ box.y2 = by2;
+
+ if ((box.x1 < box.x2) && (box.y1 < box.y2)) {
+ int n = REGION_NUM_RECTS (prgnClip);
+ BoxPtr pbox = REGION_RECTS(prgnClip);
+
+ /* Clip the rectangle to each box in the clip region
+ * this is logically equivalent to calling Intersect()
+ */
+ while(n--) {
+ pboxClipped->x1 = max(box.x1, pbox->x1);
+ pboxClipped->y1 = max(box.y1, pbox->y1);
+ pboxClipped->x2 = min(box.x2, pbox->x2);
+ pboxClipped->y2 = min(box.y2, pbox->y2);
+ pbox++;
+
+ /* see if clipping left anything */
+ if(pboxClipped->x1 < pboxClipped->x2 &&
+ pboxClipped->y1 < pboxClipped->y2)
+ pboxClipped++;
+ }
+ }
+ }
+
+ if (pboxClipped != pboxClippedBase) {
+ ffb_fbcPtr ffb = pFfb->regs;
+ int num = (pboxClipped - pboxClippedBase);
+
+ FFB_ATTR_RAW(pFfb,
+ FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST | FFB_PPC_XS_WID,
+ FFB_PPC_APE_MASK | FFB_PPC_CS_MASK | FFB_PPC_XS_MASK,
+ pGC->planemask,
+ ((FFB_ROP_EDIT_BIT | pGC->alu) | (FFB_ROP_NEW << 8)),
+ FFB_DRAWOP_RECTANGLE,
+ pGC->fgPixel,
+ fbc, pFfbPrivWin->wid);
+
+ pboxClipped = pboxClippedBase;
+ while (num--) {
+ int xx, yy, ww, hh;
+
+ xx = pboxClipped->x1;
+ yy = pboxClipped->y1;
+ ww = (pboxClipped->x2 - xx);
+ hh = (pboxClipped->y2 - yy);
+ FFBFifo(pFfb, 4);
+ FFB_WRITE64(&ffb->by, yy, xx);
+ FFB_WRITE64_2(&ffb->bh, hh, ww);
+ }
+ }
+
+ DEALLOCATE_LOCAL (pboxClippedBase);
+}
+
+static int
+FFBDbeAllocBackBufferName(WindowPtr pWin, XID bufId, int swapAction)
+{
+ ScreenPtr pScreen;
+ FFBPtr pFfb;
+ DbeWindowPrivPtr pDbeWindowPriv;
+ FFBDbeWindowPrivPrivPtr pDbeWindowPrivPriv;
+ DbeScreenPrivPtr pDbeScreenPriv;
+ GCPtr pGC;
+ xRectangle clearRect;
+
+ pScreen = pWin->drawable.pScreen;
+ pDbeWindowPriv = DBE_WINDOW_PRIV(pWin);
+ pFfb = GET_FFB_FROM_SCREEN(pScreen);
+
+ pDbeWindowPrivPriv = FFB_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv);
+ if (pDbeWindowPriv->nBufferIDs == 0) {
+ /* There is no buffer associated with the window.
+ * We have to create the window priv priv. Remember, the window
+ * priv was created at the DIX level, so all we need to do is
+ * create the priv priv and attach it to the priv.
+ */
+ pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen);
+
+ /* Setup the window priv priv. */
+ pDbeWindowPrivPriv->pDbeWindowPriv = pDbeWindowPriv;
+
+ if (!pFfb->NoAccel && pFfb->has_double_buffer) {
+ CreatorPrivWinPtr pFfbPrivWin;
+ unsigned int wid, fbc;
+
+ /* We just render directly into the hardware, all
+ * that is needed is to swap the rendering attributes
+ * and the WID settings during a swap.
+ */
+ if (!AddResource(bufId, dbeDrawableResType,
+ (pointer)&pWin->drawable)) {
+ /* Free the buffer and the drawable resource. */
+ FreeResource(bufId, RT_NONE);
+ return BadAlloc;
+ }
+
+ pFfbPrivWin = CreatorGetWindowPrivate(pWin);
+ wid = FFBWidUnshare(pFfb, pFfbPrivWin->wid);
+ if (wid == (unsigned int)-1)
+ return BadAlloc;
+
+ pFfbPrivWin->wid = wid;
+
+ /* Attach the priv priv to the priv. */
+ pDbeWindowPriv->devPrivates[FFBDbeWindowPrivPrivIndex].ptr =
+ (pointer)pDbeWindowPrivPriv;
+
+ /* Indicate we are doing hw acceleration. */
+ pDbeWindowPrivPriv->HwAccelerated = 1;
+
+ /* Start rendering into buffer B. */
+ pDbeWindowPrivPriv->HwCurrentBuf = 1;
+
+ /* No back/front temporary pixmaps. */
+ pDbeWindowPrivPriv->pFrontBuffer = NULL;
+ pDbeWindowPrivPriv->pBackBuffer = NULL;
+
+ /* Switch to writing into buffer B. */
+ fbc = pFfbPrivWin->fbc_base;
+ fbc &= ~(FFB_FBC_WB_MASK | FFB_FBC_RB_MASK);
+ fbc |= (FFB_FBC_WB_B | FFB_FBC_RB_B);
+ pFfbPrivWin->fbc_base = fbc;
+
+ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
+
+ /* Fill X plane of front and back buffers. */
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC(&pWin->drawable, pGC);
+ FFBDbeUpdateWidPlane(pWin, pGC);
+ }
+
+ /* Clear out buffer B. */
+ clearRect.x = clearRect.y = 0;
+ clearRect.width = pWin->drawable.width;
+ clearRect.height = pWin->drawable.height;
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC(&pWin->drawable, pGC);
+ (*pGC->ops->PolyFillRect)(&pWin->drawable, pGC, 1, &clearRect);
+ }
+
+ FreeScratchGC(pGC);
+ } else {
+ /* Get a front pixmap. */
+ if (!(pDbeWindowPrivPriv->pFrontBuffer =
+ (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width,
+ pDbeWindowPriv->height,
+ pWin->drawable.depth)))
+ return BadAlloc;
+
+ /* Get a back pixmap. */
+ if (!(pDbeWindowPrivPriv->pBackBuffer =
+ (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width,
+ pDbeWindowPriv->height,
+ pWin->drawable.depth))) {
+ (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer);
+ return BadAlloc;
+ }
+
+
+ /* Make the back pixmap a DBE drawable resource. */
+ if (!AddResource(bufId, dbeDrawableResType,
+ (pointer)pDbeWindowPrivPriv->pBackBuffer)) {
+ /* Free the buffer and the drawable resource. */
+ FreeResource(bufId, RT_NONE);
+ return(BadAlloc);
+ }
+
+ /* Attach the priv priv to the priv. */
+ pDbeWindowPriv->devPrivates[FFBDbeWindowPrivPrivIndex].ptr =
+ (pointer)pDbeWindowPrivPriv;
+
+ /* Indicate we are doing this non-accelerated. */
+ pDbeWindowPrivPriv->HwAccelerated = 0;
+
+ /* Clear the back buffer. */
+ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC);
+ clearRect.x = clearRect.y = 0;
+ clearRect.width = pDbeWindowPrivPriv->pBackBuffer->drawable.width;
+ clearRect.height = pDbeWindowPrivPriv->pBackBuffer->drawable.height;
+ (*pGC->ops->PolyFillRect)(
+ (DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC, 1,
+ &clearRect);
+ }
+ FreeScratchGC(pGC);
+ }
+ } else {
+ pointer cookie;
+
+ /* A buffer is already associated with the window.
+ * Place the new buffer ID information at the head of the ID list.
+ */
+ if (pDbeWindowPrivPriv->HwAccelerated != 0)
+ cookie = (pointer)&pWin->drawable;
+ else
+ cookie = (pointer)pDbeWindowPrivPriv->pBackBuffer;
+
+ /* Associate the new ID with an existing pixmap. */
+ if (!AddResource(bufId, dbeDrawableResType, cookie))
+ return BadAlloc;
+ }
+
+ return Success;
+}
+
+static void
+FFBDbeAliasBuffers(DbeWindowPrivPtr pDbeWindowPriv)
+{
+ FFBDbeWindowPrivPrivPtr pDbeWindowPrivPriv =
+ FFB_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv);
+ pointer cookie;
+ int i;
+
+ if (pDbeWindowPrivPriv->HwAccelerated != 0)
+ cookie = (pointer) &pDbeWindowPriv->pWindow->drawable;
+ else
+ cookie = (pointer) pDbeWindowPrivPriv->pBackBuffer;
+
+ for (i = 0; i < pDbeWindowPriv->nBufferIDs; i++)
+ ChangeResourceValue(pDbeWindowPriv->IDs[i], dbeDrawableResType, cookie);
+}
+
+static int
+FFBDbeSwapBuffers(ClientPtr client, int *pNumWindows, DbeSwapInfoPtr swapInfo)
+{
+ FFBDbeWindowPrivPrivPtr pDbeWindowPrivPriv;
+ DbeScreenPrivPtr pDbeScreenPriv;
+ PixmapPtr pTmpBuffer;
+ xRectangle clearRect;
+ WindowPtr pWin;
+ GCPtr pGC;
+
+ pWin = swapInfo[0].pWindow;
+ pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(pWin);
+ pDbeWindowPrivPriv = FFB_DBE_WINDOW_PRIV_PRIV_FROM_WINDOW(pWin);
+ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
+
+ if (pDbeWindowPrivPriv->HwAccelerated != 0) {
+ FFBPtr pFfb = GET_FFB_FROM_SCREEN(pWin->drawable.pScreen);
+ CreatorPrivWinPtr pFfbPrivWin = CreatorGetWindowPrivate(pWin);
+ unsigned int fbc;
+ int visible;
+
+ /* Unfortunately, this is necessary for correctness. */
+ FFBWait(pFfb, pFfb->regs);
+
+ /* Flip front/back in the WID. */
+ visible = 0;
+ if (pWin->viewable &&
+ pWin->visibility != VisibilityFullyObscured)
+ visible = 1;
+ FFBWidChangeBuffer(pFfb, pFfbPrivWin->wid, visible);
+
+ /* Indicate where we are rendering now. */
+ pDbeWindowPrivPriv->HwCurrentBuf ^= 1;
+
+ /* Update framebuffer controls. */
+ fbc = pFfbPrivWin->fbc_base;
+ fbc &= ~(FFB_FBC_WB_MASK | FFB_FBC_RB_MASK);
+ if (pDbeWindowPrivPriv->HwCurrentBuf == 0)
+ fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A;
+ else
+ fbc |= FFB_FBC_WB_B | FFB_FBC_RB_B;
+
+ /* For XdbeUndefined we do not have to do anything.
+ * This is true for XdbeUntouched as well because we
+ * do in fact retain the unobscured contents of the
+ * front buffer while it is being displayed, thus now
+ * when it has become the back buffer it is still holding
+ * those contents.
+ *
+ * The XdbeUntouched case is important because most apps
+ * using dbe use this type of swap.
+ */
+
+ if (swapInfo[0].swapAction == XdbeCopied) {
+ unsigned int fbc_front_to_back;
+
+ /* Do a GCOPY, front to back. */
+ fbc_front_to_back = fbc & ~FFB_FBC_RB_MASK;
+ if (pDbeWindowPrivPriv->HwCurrentBuf == 0)
+ fbc_front_to_back |= FFB_FBC_RB_B;
+ else
+ fbc_front_to_back |= FFB_FBC_RB_A;
+
+ pFfbPrivWin->fbc_base = fbc_front_to_back;
+ ValidateGC(&pWin->drawable, pGC);
+ (*pGC->ops->CopyArea)(&pWin->drawable,
+ &pWin->drawable,
+ pGC,
+ 0, 0,
+ pWin->drawable.width,
+ pWin->drawable.height,
+ 0, 0);
+ } else if (swapInfo[0].swapAction == XdbeBackground) {
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC(&pWin->drawable, pGC);
+ clearRect.x = 0;
+ clearRect.y = 0;
+ clearRect.width = pWin->drawable.width;
+ clearRect.height = pWin->drawable.height;
+ (*pGC->ops->PolyFillRect)(&pWin->drawable, pGC,
+ 1, &clearRect);
+ }
+ }
+
+ /* Ok, now render with these fb controls. */
+ pFfbPrivWin->fbc_base = fbc;
+ } else {
+ if (swapInfo[0].swapAction == XdbeUntouched) {
+ ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer, pGC);
+ (*pGC->ops->CopyArea)((DrawablePtr)pWin,
+ (DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer,
+ pGC, 0, 0, pWin->drawable.width,
+ pWin->drawable.height, 0, 0);
+ }
+
+ ValidateGC((DrawablePtr)pWin, pGC);
+ (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer,
+ (DrawablePtr)pWin, pGC, 0, 0,
+ pWin->drawable.width, pWin->drawable.height,
+ 0, 0);
+
+ if (swapInfo[0].swapAction == XdbeBackground) {
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer,
+ pGC);
+ clearRect.x = 0;
+ clearRect.y = 0;
+ clearRect.width =
+ pDbeWindowPrivPriv->pBackBuffer->drawable.width;
+ clearRect.height =
+ pDbeWindowPrivPriv->pBackBuffer->drawable.height;
+ (*pGC->ops->PolyFillRect)(
+ (DrawablePtr)pDbeWindowPrivPriv->pBackBuffer,
+ pGC, 1, &clearRect);
+ }
+ } else if (swapInfo[0].swapAction == XdbeUntouched) {
+ /* Swap pixmap pointers. */
+ pTmpBuffer = pDbeWindowPrivPriv->pBackBuffer;
+ pDbeWindowPrivPriv->pBackBuffer =
+ pDbeWindowPrivPriv->pFrontBuffer;
+ pDbeWindowPrivPriv->pFrontBuffer = pTmpBuffer;
+ FFBDbeAliasBuffers(pDbeWindowPrivPriv->pDbeWindowPriv);
+ }
+ }
+
+ /* Remove the swapped window from the swap information array and decrement
+ * pNumWindows to indicate to the DIX level how many windows were actually
+ * swapped.
+ */
+ if (*pNumWindows > 1) {
+ /* We were told to swap more than one window, but we only swapped the
+ * first one. Remove the first window in the list by moving the last
+ * window to the beginning.
+ */
+ swapInfo[0].pWindow = swapInfo[*pNumWindows - 1].pWindow;
+ swapInfo[0].swapAction = swapInfo[*pNumWindows - 1].swapAction;
+
+ /* Clear the last window information just to be safe. */
+ swapInfo[*pNumWindows - 1].pWindow = (WindowPtr)NULL;
+ swapInfo[*pNumWindows - 1].swapAction = 0;
+ } else {
+ /* Clear the window information just to be safe. */
+ swapInfo[0].pWindow = (WindowPtr)NULL;
+ swapInfo[0].swapAction = 0;
+ }
+
+ (*pNumWindows)--;
+
+ FreeScratchGC(pGC);
+
+ return Success;
+}
+
+static void
+FFBDbeWinPrivDelete(DbeWindowPrivPtr pDbeWindowPriv, XID bufId)
+{
+ WindowPtr pWin = pDbeWindowPriv->pWindow;
+ FFBDbeWindowPrivPrivPtr pDbeWindowPrivPriv;
+
+ if (pDbeWindowPriv->nBufferIDs != 0) {
+ /* We still have at least one more buffer ID associated with this
+ * window.
+ */
+ return;
+ }
+
+ /* We have no more buffer IDs associated with this window. We need to
+ * free some stuff.
+ */
+ pDbeWindowPrivPriv = FFB_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv);
+
+ /* If we were accelerating we need to restore the framebuffer
+ * attributes. We need to also free up the Dbe WID and go
+ * back to using the shared one.
+ */
+ if (pDbeWindowPrivPriv->HwAccelerated != 0) {
+ FFBPtr pFfb = GET_FFB_FROM_SCREEN(pWin->drawable.pScreen);
+ CreatorPrivWinPtr pFfbPrivWin = CreatorGetWindowPrivate(pWin);
+ xRectangle clearRect;
+ unsigned int fbc;
+ GCPtr pGC;
+
+ pFfbPrivWin->wid = FFBWidReshare(pFfb, pFfbPrivWin->wid);
+
+ /* Go back to using buffer A. */
+ fbc = pFfbPrivWin->fbc_base;
+ fbc &= ~(FFB_FBC_WB_MASK | FFB_FBC_RB_MASK);
+ fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A;
+
+ /* Now fixup the WID channel. */
+ pFfbPrivWin->fbc_base =
+ (fbc & ~FFB_FBC_RGBE_MASK) | FFB_FBC_RGBE_OFF;
+
+ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen);
+ clearRect.x = clearRect.y = 0;
+ clearRect.width = pWin->drawable.width;
+ clearRect.height = pWin->drawable.height;
+ ValidateGC(&pWin->drawable, pGC);
+ FFBDbeUpdateWidPlane(pWin, pGC);
+ (*pGC->ops->PolyFillRect)(&pWin->drawable, pGC, 1, &clearRect);
+ FreeScratchGC(pGC);
+
+ pFfbPrivWin->fbc_base = fbc;
+ } else {
+ /* Destroy the front and back pixmaps. */
+ if (pDbeWindowPrivPriv->pFrontBuffer)
+ (*pDbeWindowPriv->pWindow->drawable.pScreen->DestroyPixmap)(
+ pDbeWindowPrivPriv->pFrontBuffer);
+ if (pDbeWindowPrivPriv->pBackBuffer)
+ (*pDbeWindowPriv->pWindow->drawable.pScreen->DestroyPixmap)(
+ pDbeWindowPrivPriv->pBackBuffer);
+ }
+}
+
+static Bool
+FFBDbePositionWindow(WindowPtr pWin, int x, int y)
+{
+ ScreenPtr pScreen;
+ DbeScreenPrivPtr pDbeScreenPriv;
+ DbeWindowPrivPtr pDbeWindowPriv;
+ FFBDbeWindowPrivPrivPtr pDbeWindowPrivPriv;
+ int width, height;
+ int dx, dy, dw, dh;
+ int sourcex, sourcey;
+ int destx, desty;
+ int savewidth, saveheight;
+ PixmapPtr pFrontBuffer;
+ PixmapPtr pBackBuffer;
+ Bool clear;
+ GCPtr pGC;
+ xRectangle clearRect;
+ Bool ret;
+
+ /* 1. Unwrap the member routine. */
+ pScreen = pWin->drawable.pScreen;
+ pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen);
+ pScreen->PositionWindow = pDbeScreenPriv->PositionWindow;
+
+ /* 2. Do any work necessary before the member routine is called.
+ *
+ * In this case we do not need to do anything.
+ */
+
+ /* 3. Call the member routine, saving its result if necessary. */
+ ret = (*pScreen->PositionWindow)(pWin, x, y);
+
+ /* 4. Rewrap the member routine, restoring the wrapper value first in case
+ * the wrapper (or something that it wrapped) change this value.
+ */
+ pDbeScreenPriv->PositionWindow = pScreen->PositionWindow;
+ pScreen->PositionWindow = FFBDbePositionWindow;
+
+ /* 5. Do any work necessary after the member routine has been called. */
+ if (!(pDbeWindowPriv = DBE_WINDOW_PRIV(pWin)))
+ return ret;
+
+ if (pDbeWindowPriv->width == pWin->drawable.width &&
+ pDbeWindowPriv->height == pWin->drawable.height)
+ return ret;
+
+ width = pWin->drawable.width;
+ height = pWin->drawable.height;
+
+ dx = pWin->drawable.x - pDbeWindowPriv->x;
+ dy = pWin->drawable.y - pDbeWindowPriv->y;
+ dw = width - pDbeWindowPriv->width;
+ dh = height - pDbeWindowPriv->height;
+
+ GravityTranslate (0, 0, -dx, -dy, dw, dh, pWin->bitGravity, &destx, &desty);
+
+ clear = ((pDbeWindowPriv->width < (unsigned short)width ) ||
+ (pDbeWindowPriv->height < (unsigned short)height) ||
+ (pWin->bitGravity == ForgetGravity));
+
+ sourcex = 0;
+ sourcey = 0;
+ savewidth = pDbeWindowPriv->width;
+ saveheight = pDbeWindowPriv->height;
+
+ /* Clip rectangle to source and destination. */
+ if (destx < 0) {
+ savewidth += destx;
+ sourcex -= destx;
+ destx = 0;
+ }
+
+ if (destx + savewidth > width)
+ savewidth = width - destx;
+
+ if (desty < 0) {
+ saveheight += desty;
+ sourcey -= desty;
+ desty = 0;
+ }
+
+ if (desty + saveheight > height)
+ saveheight = height - desty;
+
+ pDbeWindowPriv->width = width;
+ pDbeWindowPriv->height = height;
+ pDbeWindowPriv->x = pWin->drawable.x;
+ pDbeWindowPriv->y = pWin->drawable.y;
+
+ pGC = GetScratchGC (pWin->drawable.depth, pScreen);
+
+ if (clear) {
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ clearRect.x = 0;
+ clearRect.y = 0;
+ clearRect.width = width;
+ clearRect.height = height;
+ } else {
+ clear = FALSE;
+ }
+ }
+
+ pDbeWindowPrivPriv = FFB_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv);
+ if (pDbeWindowPrivPriv->HwAccelerated != 0) {
+ /* If we're hw accelerating, things are much easier. */
+ ValidateGC(&pWin->drawable, pGC);
+ FFBDbeUpdateWidPlane(pWin, pGC);
+ if (clear) {
+ CreatorPrivWinPtr pFfbPrivWin = CreatorGetWindowPrivate(pWin);
+ unsigned int fbc, orig_fbc;
+
+ ValidateGC(&pWin->drawable, pGC);
+ (*pGC->ops->PolyFillRect)(&pWin->drawable, pGC,
+ 1, &clearRect);
+
+ orig_fbc = fbc = pFfbPrivWin->fbc_base;
+ fbc &= ~(FFB_FBC_WB_MASK);
+ if (pDbeWindowPrivPriv->HwCurrentBuf == 0)
+ fbc |= FFB_FBC_WB_B;
+ else
+ fbc |= FFB_FBC_WB_A;
+
+ pFfbPrivWin->fbc_base = fbc;
+
+ if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) {
+ ValidateGC(&pWin->drawable, pGC);
+ clearRect.x = 0;
+ clearRect.y = 0;
+ clearRect.width = width;
+ clearRect.height = height;
+ (*pGC->ops->PolyFillRect)(&pWin->drawable, pGC,
+ 1, &clearRect);
+ }
+
+ pFfbPrivWin->fbc_base = orig_fbc;
+ }
+
+ FreeScratchGC(pGC);
+ } else {
+ /* Create DBE buffer pixmaps equal to size of resized window. */
+ pFrontBuffer = (*pScreen->CreatePixmap)(pScreen, width, height,
+ pWin->drawable.depth);
+
+ pBackBuffer = (*pScreen->CreatePixmap)(pScreen, width, height,
+ pWin->drawable.depth);
+
+ if (!pFrontBuffer || !pBackBuffer) {
+ /* We failed at creating 1 or 2 of the pixmaps. */
+ if (pFrontBuffer)
+ (*pScreen->DestroyPixmap)(pFrontBuffer);
+ if (pBackBuffer)
+ (*pScreen->DestroyPixmap)(pBackBuffer);
+
+ /* Destroy all buffers for this window. */
+ while (pDbeWindowPriv) {
+ /* DbeWindowPrivDelete() will free the window private
+ * if there no more buffer IDs associated with this
+ * window.
+ */
+ FreeResource(pDbeWindowPriv->IDs[0], RT_NONE);
+ pDbeWindowPriv = DBE_WINDOW_PRIV(pWin);
+ }
+ FreeScratchGC(pGC);
+ return FALSE;
+ } else {
+ /* Clear out the new DBE buffer pixmaps. */
+ ValidateGC((DrawablePtr)pFrontBuffer, pGC);
+
+ /* I suppose this could avoid quite a bit of work if
+ * it computed the minimal area required.
+ */
+ if (clear) {
+ (*pGC->ops->PolyFillRect)((DrawablePtr)pFrontBuffer, pGC, 1,
+ &clearRect);
+ (*pGC->ops->PolyFillRect)((DrawablePtr)pBackBuffer , pGC, 1,
+ &clearRect);
+ }
+
+ /* Copy the contents of the old DBE pixmaps to the new pixmaps. */
+ if (pWin->bitGravity != ForgetGravity) {
+ (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer,
+ (DrawablePtr)pFrontBuffer, pGC,
+ sourcex, sourcey,
+ savewidth, saveheight,
+ destx, desty);
+ (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer,
+ (DrawablePtr)pBackBuffer, pGC,
+ sourcex, sourcey,
+ savewidth, saveheight, destx, desty);
+ }
+
+ /* Destroy the old pixmaps, and point the DBE window priv to the new
+ * pixmaps.
+ */
+ (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer);
+ (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pBackBuffer);
+
+ pDbeWindowPrivPriv->pFrontBuffer = pFrontBuffer;
+ pDbeWindowPrivPriv->pBackBuffer = pBackBuffer;
+
+ /* Make sure all XID are associated with the new back pixmap. */
+ FFBDbeAliasBuffers(pDbeWindowPriv);
+
+ FreeScratchGC(pGC);
+ }
+ }
+
+ return ret;
+}
+
+static void
+FFBDbeResetProc(ScreenPtr pScreen)
+{
+ DbeScreenPrivPtr pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen);
+
+ /* Unwrap wrappers */
+ pScreen->PositionWindow = pDbeScreenPriv->PositionWindow;
+}
+
+static Bool
+FFBDbeInit(ScreenPtr pScreen, DbeScreenPrivPtr pDbeScreenPriv)
+{
+ ScrnInfoPtr pScrn;
+ FFBPtr pFfb;
+
+ pScrn = xf86Screens[pScreen->myNum];
+ pFfb = GET_FFB_FROM_SCRN(pScrn);
+ xf86Msg(X_INFO, "%s: Setting up double-buffer acceleration.\n",
+ pFfb->psdp->device);
+
+ /* Copy resource types created by DIX */
+ dbeDrawableResType = pDbeScreenPriv->dbeDrawableResType;
+ dbeWindowPrivResType = pDbeScreenPriv->dbeWindowPrivResType;
+
+ /* Copy private indices created by DIX */
+ dbeScreenPrivIndex = pDbeScreenPriv->dbeScreenPrivIndex;
+ dbeWindowPrivIndex = pDbeScreenPriv->dbeWindowPrivIndex;
+
+ /* Reset the window priv privs if generations do not match. */
+ if (FFBDbePrivPrivGeneration != serverGeneration) {
+ /* Allocate the window priv priv. */
+ FFBDbeWindowPrivPrivIndex = (*pDbeScreenPriv->AllocWinPrivPrivIndex)();
+
+ if (!(*pDbeScreenPriv->AllocWinPrivPriv)(pScreen,
+ FFBDbeWindowPrivPrivIndex,
+ sizeof(FFBDbeWindowPrivPrivRec)))
+ return FALSE;
+
+ /* Make sure we only do this code once. */
+ FFBDbePrivPrivGeneration = serverGeneration;
+ }
+
+ /* Wrap functions. */
+ pDbeScreenPriv->PositionWindow = pScreen->PositionWindow;
+ pScreen->PositionWindow = FFBDbePositionWindow;
+
+ /* Initialize the per-screen DBE function pointers. */
+ pDbeScreenPriv->GetVisualInfo = FFBDbeGetVisualInfo;
+ pDbeScreenPriv->AllocBackBufferName = FFBDbeAllocBackBufferName;
+ pDbeScreenPriv->SwapBuffers = FFBDbeSwapBuffers;
+ pDbeScreenPriv->BeginIdiom = 0;
+ pDbeScreenPriv->EndIdiom = 0;
+ pDbeScreenPriv->ResetProc = FFBDbeResetProc;
+ pDbeScreenPriv->WinPrivDelete = FFBDbeWinPrivDelete;
+
+ /* The FFB implementation doesn't need buffer validation. */
+ pDbeScreenPriv->ValidateBuffer = (void (*)())NoopDDA;
+
+ return TRUE;
+}
+
+extern void DbeRegisterFunction(ScreenPtr pScreen, Bool (*funct)(ScreenPtr, DbeScreenPrivPtr));
+
+Bool
+FFBDbePreInit(ScreenPtr pScreen)
+{
+ DbeRegisterFunction(pScreen, FFBDbeInit);
+ return TRUE;
+}