Index: exa.c =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/exa/exa.c,v retrieving revision 1.30 diff -u -r1.30 exa.c --- exa.c 6 Nov 2005 16:40:59 -0000 1.30 +++ exa.c 22 Jan 2006 23:43:21 -0000 @@ -203,7 +203,7 @@ if (!pExaPixmap->area) return FALSE; - DBG_PIXMAP(("++ 0x%lx (0x%x) (%dx%d)\n", pPixmap->drawable.id, + DBG_PIXMAP(("++ %p 0x%lx (0x%x) (%dx%d)\n", pPixmap, pPixmap->drawable.id, (ExaGetPixmapPriv(pPixmap)->area ? ExaGetPixmapPriv(pPixmap)->area->offset : 0), pPixmap->drawable.width, @@ -253,6 +253,7 @@ } pExaPixmap->dirty = FALSE; + /* return; XXX HACK HACK HACK */ if (pExaScr->info->accel.UploadToScreen) { @@ -403,8 +404,8 @@ ExaPixmapPriv (pPixmap); if (pExaPixmap->area) { - DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n", - (void*)pPixmap->drawable.id, + DBG_PIXMAP(("-- %p 0x%lx (0x%x) (%dx%d)\n", pPixmap, + pPixmap->drawable.id, ExaGetPixmapPriv(pPixmap)->area->offset, pPixmap->drawable.width, pPixmap->drawable.height)); @@ -666,6 +667,111 @@ exaMarkSync(pScreen); } +static void +exaPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + PixmapPtr pPix = NULL, pScratch = NULL; + int xi, yi, pitch; + unsigned long destMask; + + Bool (*uploadToScreen)(PixmapPtr, int, int, int, int, char *, int); + uploadToScreen = pExaScr->info->accel.UploadToScreen; + + if (!pScrn->vtSema) + goto fallback; + + /* + * additional GC validation because PutImage cares. we could do better + * if we clipped out subwindows in ClipByChildren mode or when the client + * gives a non-null clip list, and then iterated over each rect. not now + * though. + */ +#if 0 + if (pGC->subWindowMode != IncludeInferiors || pGC->clientClip) + goto fallback; +#endif + + pPix = exaGetOffscreenPixmap(pDrawable, &xi, &yi); + xi += pDrawable->x; + yi += pDrawable->y; + + if (pPix && pPix->drawable.bitsPerPixel >= 8) { + + pitch = w * (pPix->drawable.bitsPerPixel / 8); + destMask = (1 << pPix->drawable.bitsPerPixel) - 1; + if (pGC->alu == GXcopy && (pGC->planemask & destMask) == destMask && format == ZPixmap && + uploadToScreen && + uploadToScreen(pPix, x + xi, y + yi, w, h, bits, pitch)) { + exaDrawableDirty(pDrawable); + return; + } + + pScratch = pScreen->CreatePixmap(pScreen, w, h, pPix->drawable.depth); + if (!pScratch) + goto fallback; + + /* card memory is implicitly ZPixmap, so convert if necessary. */ + if (format != ZPixmap) { + /* + * this kinda sucks. we'd rather do the rop on card if possible, + * but we're not allowed to migrate anything between PrepareCopy + * and Copy. so, do the conversion as GXcopy in host memory, and + * assume that the driver can do rops in hardware. + */ + int alu = pGC->alu; + int planemask = pGC->planemask; + + pGC->alu = GXcopy; + pGC->planemask = -1; + fbPutImage((DrawablePtr)pScratch, pGC, depth, 0, 0, w, h, leftPad, + format, bits); + pGC->alu = alu; + pGC->planemask = planemask; + + exaPixmapUseScreen(pScratch); /* will hit UTS if available */ + if (!exaPixmapIsOffscreen(pScratch)) + goto destroy_and_fallback; + } else { + /* + * FIXME: Even though we haven't inited the contents of pScratch + * yet, UseScreen will UTS them, so we're doing useless work. + * Need to fix UseScreen to only upload when "dirty". + */ + exaPixmapUseScreen(pScratch); /* will hit UTS if available */ + if (!exaPixmapIsOffscreen(pScratch)) + goto destroy_and_fallback; + + if (!uploadToScreen(pScratch, 0, 0, w, h, bits, pitch)) + goto destroy_and_fallback; + } + + if (!pExaScr->info->accel.PrepareCopy(pScratch, pPix, w, h, pGC->alu, + pGC->planemask)) + goto destroy_and_fallback; + pExaScr->info->accel.Copy(pPix, 0, 0, x, y, w, h); + pExaScr->info->accel.DoneCopy(pPix); + exaMarkSync(pScreen); + + pScreen->DestroyPixmap(pScratch); + + exaDrawableDirty(pDrawable); + + return; + } + +destroy_and_fallback: + if (pScratch) + pScreen->DestroyPixmap(pScratch); + +fallback: + ExaCheckPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); +} + void exaCopyNtoN (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, @@ -1077,7 +1183,7 @@ static const GCOps exaOps = { exaFillSpans, ExaCheckSetSpans, - ExaCheckPutImage, + exaPutImage, exaCopyArea, ExaCheckCopyPlane, ExaCheckPolyPoint, @@ -1101,7 +1207,7 @@ }; static void -exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) +exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { fbValidateGC (pGC, changes, pDrawable); @@ -1370,6 +1476,82 @@ ExaCheckPaintWindow (pWin, pRegion, what); } +static void +exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ScreenPtr pScreen = pDrawable->pScreen; + ExaScreenPriv(pScreen); + ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen); + PixmapPtr pPix = NULL, pScratch = NULL; + int xi, yi, pitch; + unsigned long destMask; + + if (!pScrn->vtSema) + goto fallback; + + Bool (*downloadFromScreen)(PixmapPtr, int, int, int, int, char *, int); + + downloadFromScreen = pExaScr->info->accel.DownloadFromScreen; + pPix = exaGetOffscreenPixmap(pDrawable, &xi, &yi); + xi += pDrawable->x; + yi += pDrawable->y; + + if (pPix && pPix->drawable.bitsPerPixel >= 8) { + + pitch = w * (pPix->drawable.bitsPerPixel / 8); + + /* try the easy way */ + + destMask = (1 << pPix->drawable.bitsPerPixel) -1; + if (format == ZPixmap && (planeMask & destMask) == destMask && downloadFromScreen) + if (downloadFromScreen(pPix, x + xi, y + yi, w, h, d, pitch)) + return; + + pScratch = pScreen->CreatePixmap(pScreen, w, h, pPix->drawable.depth); + if (!pScratch) + goto fallback; + exaPixmapUseScreen(pScratch); + + if (!pExaScr->info->accel.PrepareCopy(pPix, pScratch, w, h, GXcopy, + planeMask)) + goto destroy_and_fallback; + pExaScr->info->accel.Copy(pScratch, x + xi, y + yi, 0, 0, w, h); + pExaScr->info->accel.DoneCopy(pScratch); + exaMarkSync(pScreen); + + if (format == ZPixmap && downloadFromScreen) { + /* the framebuffer is implicitly ZPixmap, so just kick DMA */ + if (!downloadFromScreen(pScratch, 0, 0, w, h, d, pitch)) + goto destroy_and_fallback; + } else { + /* + * migrate the pixmap back to host memory, and do the blit + * conversion in software, which is as fast as we can get. this + * ignores pixmap scoring, but we're going to free the scratch + * immediately anyway. XXX fbGetImage is still pretty slow. + */ + exaMoveOutPixmap(pScratch); + fbGetImage((DrawablePtr)pScratch, 0, 0, w, h, format, -1, d); + } + + pScreen->DestroyPixmap(pScratch); + return; + + } + /* + * If we get here it's almost always because the GetImage source + * wasn't in card memory to begin with. No big deal, the fallback + * is as fast as we can get anyway. + */ + +destroy_and_fallback: + if (pScratch) + pScreen->DestroyPixmap(pScratch); + +fallback: + ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d); +} static Bool exaCloseScreen(int i, ScreenPtr pScreen) @@ -1444,7 +1626,7 @@ pScreen->CreateGC = exaCreateGC; pExaScr->SavedGetImage = pScreen->GetImage; - pScreen->GetImage = ExaCheckGetImage; + pScreen->GetImage = exaGetImage; pExaScr->SavedGetSpans = pScreen->GetSpans; pScreen->GetSpans = ExaCheckGetSpans;