/* * Copyright © 2001 Keith Packard * * Partly based on code that is Copyright © The XFree86 Project Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include #endif #include "exaPriv.h" #ifdef RENDER #include "mipict.h" #define EXA_DEBUG_FALLBACKS 0 #if EXA_DEBUG_FALLBACKS static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) { char format[20]; char size[20]; char loc; int temp; if (!pict) { snprintf(string, n, "None"); return; } switch (pict->format) { case PICT_a8r8g8b8: snprintf(format, 20, "ARGB8888"); break; case PICT_r5g6b5: snprintf(format, 20, "RGB565 "); break; case PICT_x1r5g5b5: snprintf(format, 20, "RGB555 "); break; case PICT_a8: snprintf(format, 20, "A8 "); break; case PICT_a1: snprintf(format, 20, "A1 "); break; default: snprintf(format, 20, "0x%x", (int)pict->format); break; } loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, pict->pDrawable->height, pict->repeat ? " R" : ""); snprintf(string, n, "0x%lx:%c fmt %s (%s)", (long)pict, loc, format, size); } static void exaPrintCompositeFallback(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) { char sop[20]; char srcdesc[40], maskdesc[40], dstdesc[40]; switch(op) { case PictOpSrc: sprintf(sop, "Src"); break; case PictOpOver: sprintf(sop, "Over"); break; default: sprintf(sop, "0x%x", (int)op); break; } exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); exaCompositeFallbackPictDesc(pMask, maskdesc, 40); exaCompositeFallbackPictDesc(pDst, dstdesc, 40); ErrorF("Composite fallback: op %s, \n" " src %s, \n" " mask %s, \n" " dst %s, \n", sop, srcdesc, maskdesc, dstdesc); } #endif static Bool exaGetPixelFromRGBA(CARD32 *pixel, CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha, CARD32 format) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; *pixel = 0; if (!PICT_FORMAT_COLOR(format)) return FALSE; rbits = PICT_FORMAT_R(format); gbits = PICT_FORMAT_G(format); bbits = PICT_FORMAT_B(format); abits = PICT_FORMAT_A(format); if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { bshift = 0; gshift = bbits; rshift = gshift + gbits; ashift = rshift + rbits; } else { /* PICT_TYPE_ABGR */ rshift = 0; gshift = rbits; bshift = gshift + gbits; ashift = bshift + bbits; } *pixel |= ( blue >> (16 - bbits)) << bshift; *pixel |= ( red >> (16 - rbits)) << rshift; *pixel |= (green >> (16 - gbits)) << gshift; *pixel |= (alpha >> (16 - abits)) << ashift; return TRUE; } static Bool exaGetRGBAFromPixel(CARD32 pixel, CARD16 *red, CARD16 *green, CARD16 *blue, CARD16 *alpha, CARD32 format) { int rbits, bbits, gbits, abits; int rshift, bshift, gshift, ashift; if (!PICT_FORMAT_COLOR(format)) return FALSE; rbits = PICT_FORMAT_R(format); gbits = PICT_FORMAT_G(format); bbits = PICT_FORMAT_B(format); abits = PICT_FORMAT_A(format); if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { bshift = 0; gshift = bbits; rshift = gshift + gbits; ashift = rshift + rbits; } else { /* PICT_TYPE_ABGR */ rshift = 0; gshift = rbits; bshift = gshift + gbits; ashift = bshift + bbits; } *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); while (rbits < 16) { *red |= *red >> rbits; rbits <<= 1; } *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); while (gbits < 16) { *green |= *green >> gbits; gbits <<= 1; } *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); while (bbits < 16) { *blue |= *blue >> bbits; bbits <<= 1; } if (abits) { *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); while (abits < 16) { *alpha |= *alpha >> abits; abits <<= 1; } } else *alpha = 0xffff; return TRUE; } static int exaTryDriverSolidFill(PicturePtr pSrc, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ExaScreenPriv (pDst->pDrawable->pScreen); RegionRec region; BoxPtr pbox; int nbox; int dst_off_x, dst_off_y; PixmapPtr pSrcPix, pDstPix; CARD32 pixel; CARD16 red, green, blue, alpha; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; xSrc += pSrc->pDrawable->x; ySrc += pSrc->pDrawable->y; if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, xSrc, ySrc, 0, 0, xDst, yDst, width, height)) return 1; if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable); if (pDst->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseScreen ((PixmapPtr) pDst->pDrawable); pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); if (!pDstPix) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; } if (pSrc->pDrawable->type == DRAWABLE_WINDOW) pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap)( (WindowPtr) (pSrc->pDrawable)); else pSrcPix = (PixmapPtr) (pSrc->pDrawable); /* If source is offscreen, we need to sync the accelerator * before accessing it. We'd prefer for it to be in memory. */ if (exaPixmapIsOffscreen(pSrcPix)) { exaWaitSync(pDst->pDrawable->pScreen); } pixel = *(CARD32 *)(pSrcPix->devPrivate.ptr); if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, pSrc->format)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->format); if (!(*pExaScr->info->accel.PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } nbox = REGION_NUM_RECTS(®ion); pbox = REGION_RECTS(®ion); while (nbox--) { (*pExaScr->info->accel.Solid) (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); pbox++; } (*pExaScr->info->accel.DoneSolid) (pDstPix); exaMarkSync(pDst->pDrawable->pScreen); exaDrawableDirty (pDst->pDrawable); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; } static int exaTryDriverComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ExaScreenPriv (pDst->pDrawable->pScreen); RegionRec region; BoxPtr pbox; int nbox; int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; struct _Pixmap scratch; if (pExaScr->info->card.maxX < width || pExaScr->info->card.maxY < height) { int total_width = width; int total_height = height; int xOff = 0; int yOff = 0; while (total_width > pExaScr->info->card.maxX) { while (total_height > pExaScr->info->card.maxY) { exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc + xOff, ySrc + yOff, xMask + xOff, yMask + yOff, xDst + xOff, yDst + yOff, pExaScr->info->card.maxX, pExaScr->info->card.maxY); total_width -= pExaScr->info->card.maxX; xOff += pExaScr->info->card.maxX; yOff = 0; } if (total_height) exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc + xOff, ySrc + yOff, xMask + xOff, yMask + yOff, xDst + xOff, yDst + yOff, pExaScr->info->card.maxX, total_height); total_height -= pExaScr->info->card.maxY; yOff += pExaScr->info->card.maxY; } if (total_width && total_height) exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc + xOff, ySrc + yOff, xMask + xOff, yMask + yOff, xDst + xOff, yDst + yOff, total_width, total_height); return -1; } xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; if (pMask) { xMask += pMask->pDrawable->x; yMask += pMask->pDrawable->y; } xSrc += pSrc->pDrawable->x; ySrc += pSrc->pDrawable->y; if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) return 1; if (pExaScr->info->accel.CheckComposite && !(*pExaScr->info->accel.CheckComposite) (op, pSrc, pMask, pDst)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseScreen ((PixmapPtr) pSrc->pDrawable); if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseScreen ((PixmapPtr) pMask->pDrawable); if (pDst->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseScreen ((PixmapPtr) pDst->pDrawable); pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); if (pMask) pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); if (!pDstPix) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; } if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->accel.UploadToScratch) { if (pSrc->pDrawable->type == DRAWABLE_WINDOW) pSrcPix = (*pSrc->pDrawable->pScreen->GetWindowPixmap) ( (WindowPtr) pSrc->pDrawable); else pSrcPix = (PixmapPtr) pSrc->pDrawable; if ((*pExaScr->info->accel.UploadToScratch) (pSrcPix, &scratch)) pSrcPix = &scratch; } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->accel.UploadToScratch) { if (pMask->pDrawable->type == DRAWABLE_WINDOW) pMaskPix = (*pMask->pDrawable->pScreen->GetWindowPixmap) ( (WindowPtr) pMask->pDrawable); else pMaskPix = (PixmapPtr) pMask->pDrawable; if ((*pExaScr->info->accel.UploadToScratch) (pMaskPix, &scratch)) pMaskPix = &scratch; } if (!pSrcPix || (pMask && !pMaskPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 0; } if (!(*pExaScr->info->accel.PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, pMaskPix, pDstPix)) { REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return -1; } nbox = REGION_NUM_RECTS(®ion); pbox = REGION_RECTS(®ion); xMask -= xDst; yMask -= yDst; xSrc -= xDst; ySrc -= yDst; while (nbox--) { (*pExaScr->info->accel.Composite) (pDstPix, pbox->x1 + xSrc + src_off_x, pbox->y1 + ySrc + src_off_y, pbox->x1 + xMask + mask_off_x, pbox->y1 + yMask + mask_off_y, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pbox++; } (*pExaScr->info->accel.DoneComposite) (pDstPix); exaMarkSync(pDst->pDrawable->pScreen); exaDrawableDirty (pDst->pDrawable); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; } void exaComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ExaScreenPriv (pDst->pDrawable->pScreen); int ret = -1; if (!pMask && pSrc->pDrawable) { if (op == PictOpSrc) { if (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && pSrc->repeat) { ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, width, height); if (ret == 1) return; } else if (!pSrc->repeat && !pSrc->transform && pSrc->format == pDst->format) { RegionRec region; xDst += pDst->pDrawable->x; yDst += pDst->pDrawable->y; xSrc += pSrc->pDrawable->x; ySrc += pSrc->pDrawable->y; if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) return; exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, 0, REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), xSrc - xDst, ySrc - yDst, FALSE, FALSE, 0, 0); return; } } } if (pSrc->pDrawable && (!pMask || pMask->pDrawable) && pExaScr->info->accel.PrepareComposite && !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) { ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); if (ret == 1) return; } if (ret != 0) { /* failure to accelerate was not due to pixmaps being in the wrong * locations. */ if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable); if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseMemory ((PixmapPtr) pMask->pDrawable); if (pDst->pDrawable->type == DRAWABLE_PIXMAP) exaPixmapUseMemory ((PixmapPtr) pDst->pDrawable); } #if EXA_DEBUG_FALLBACKS exaPrintCompositeFallback (op, pSrc, pMask, pDst); #endif ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); } #endif