exa.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 177 insertions(+), 5 deletions(-) Index: exa.c =================================================================== RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/exa/exa.c,v retrieving revision 1.27 diff -u -d -p -r1.27 exa.c --- exa.c 12 Oct 2005 07:35:20 -0000 1.27 +++ exa.c 15 Oct 2005 00:19:43 -0000 @@ -199,7 +199,7 @@ exaPixmapAllocArea (PixmapPtr pPixmap) 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, @@ -239,6 +239,7 @@ exaMoveInPixmap (PixmapPtr pPixmap) } pExaPixmap->dirty = FALSE; + /* return; XXX HACK HACK HACK */ if (pExaScr->info->accel.UploadToScreen) { @@ -389,8 +390,8 @@ exaDestroyPixmap (PixmapPtr pPixmap) 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)); @@ -652,6 +653,107 @@ exaFillSpans(DrawablePtr pDrawable, GCPt 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; + + 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); + + if (pPix && pPix->drawable.bitsPerPixel >= 8) { + + pitch = w * (pPix->drawable.bitsPerPixel / 8); + + if (pGC->alu == GXcopy && pGC->planemask == -1 && 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); + + 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, @@ -1063,7 +1165,7 @@ exaImageGlyphBlt (DrawablePtr pDrawable, static const GCOps exaOps = { exaFillSpans, ExaCheckSetSpans, - ExaCheckPutImage, + exaPutImage, exaCopyArea, ExaCheckCopyPlane, ExaCheckPolyPoint, @@ -1356,6 +1458,76 @@ exaPaintWindow(WindowPtr pWin, RegionPtr 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; + + if (!pScrn->vtSema) + goto fallback; + + Bool (*downloadFromScreen)(PixmapPtr, int, int, int, int, char *, int); + + downloadFromScreen = pExaScr->info->accel.DownloadFromScreen; + pPix = exaGetOffscreenPixmap(pDrawable, &xi, &yi); + + if (pPix && pPix->drawable.bitsPerPixel >= 8) { + + pitch = w * (pPix->drawable.bitsPerPixel / 8); + + /* try the easy way */ + if (format == ZPixmap && planeMask == -1 && 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); + + 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) @@ -1430,7 +1602,7 @@ exaDriverInit (ScreenPtr pScreen, pScreen->CreateGC = exaCreateGC; pExaScr->SavedGetImage = pScreen->GetImage; - pScreen->GetImage = ExaCheckGetImage; + pScreen->GetImage = exaGetImage; pExaScr->SavedGetSpans = pScreen->GetSpans; pScreen->GetSpans = ExaCheckGetSpans;