diff options
Diffstat (limited to 'src/ffb_dbe.c')
-rw-r--r-- | src/ffb_dbe.c | 902 |
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; +} |