Example #1
0
/**
 * Copies out important pixmap data and removes references to framebuffer area.
 * Called when the memory manager decides it's time to kick the pixmap out of
 * framebuffer entirely.
 */
void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
    PixmapPtr pPixmap = area->privData;
    ExaPixmapPriv(pPixmap);
    RegionPtr pDamageReg = DamageRegion(pExaPixmap->pDamage);

    DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
		  (void*)(ExaGetPixmapPriv(pPixmap)->area ?
                          ExaGetPixmapPriv(pPixmap)->area->offset : 0),
		  pPixmap->drawable.width,
		  pPixmap->drawable.height,
		  exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));

    if (exaPixmapIsOffscreen(pPixmap)) {
	exaCopyDirtyToSys (pPixmap);
	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
	pPixmap->devKind = pExaPixmap->sys_pitch;
	pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    }

    pExaPixmap->fb_ptr = NULL;
    pExaPixmap->area = NULL;

    /* Mark all valid bits as damaged, so they'll get copied to FB next time */
    REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg,
		 &pExaPixmap->validReg);
}
/**
 * Switches the current active location of the pixmap to system memory, copying
 * updated data out if necessary.
 */
static void
exaDoMoveOutPixmap(ExaMigrationPtr migrate)
{
    PixmapPtr pPixmap = migrate->pPix;

    ExaPixmapPriv(pPixmap);

    if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
        return;

    exaCopyDirtyToSys(migrate);

    if (exaPixmapHasGpuCopy(pPixmap)) {

        DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
                     (void *) (ExaGetPixmapPriv(pPixmap)->area ?
                               ExaGetPixmapPriv(pPixmap)->area->offset : 0),
                     pPixmap->drawable.width,
                     pPixmap->drawable.height,
                     exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));

        pExaPixmap->use_gpu_copy = FALSE;

        pPixmap->devKind = pExaPixmap->sys_pitch;
        pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    }
}
/**
 * Allocates a framebuffer copy of the pixmap if necessary, and then copies
 * any necessary pixmap data into the framebuffer copy and points the pixmap at
 * it.
 *
 * Note that when first allocated, a pixmap will have FALSE dirty flag.
 * This is intentional because pixmap data starts out undefined.  So if we move
 * it in due to the first operation against it being accelerated, it will have
 * undefined framebuffer contents that we didn't have to upload.  If we do
 * moveouts (and moveins) after the first movein, then we will only have to copy
 * back and forth if the pixmap was written to after the last synchronization of
 * the two copies.  Then, at exaPixmapSave (when the framebuffer copy goes away)
 * we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
 * all the data, since it's almost surely all valid now.
 */
static void
exaDoMoveInPixmap(ExaMigrationPtr migrate)
{
    PixmapPtr pPixmap = migrate->pPix;
    ScreenPtr pScreen = pPixmap->drawable.pScreen;

    ExaScreenPriv(pScreen);
    ExaPixmapPriv(pPixmap);

    /* If we're VT-switched away, no touching card memory allowed. */
    if (pExaScr->swappedOut)
        return;

    /* If we're not allowed to move, then fail. */
    if (exaPixmapIsPinned(pPixmap))
        return;

    /* Don't migrate in pixmaps which are less than 8bpp.  This avoids a lot of
     * fragility in EXA, and <8bpp is probably not used enough any more to care
     * (at least, not in acceleratd paths).
     */
    if (pPixmap->drawable.bitsPerPixel < 8)
        return;

    if (pExaPixmap->accel_blocked)
        return;

    if (pExaPixmap->area == NULL) {
        pExaPixmap->area =
            exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
                              pExaScr->info->pixmapOffsetAlign, FALSE,
                              exaPixmapSave, (pointer) pPixmap);
        if (pExaPixmap->area == NULL)
            return;

        pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
                             pExaPixmap->area->offset;
    }

    exaCopyDirtyToFb(migrate);

    if (exaPixmapHasGpuCopy(pPixmap))
        return;

    DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
                 (ExaGetPixmapPriv(pPixmap)->area ?
                  ExaGetPixmapPriv(pPixmap)->area->offset : 0),
                 pPixmap->drawable.width,
                 pPixmap->drawable.height,
                 exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));

    pExaPixmap->use_gpu_copy = TRUE;

    pPixmap->devKind = pExaPixmap->fb_pitch;
    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
Example #4
0
/**
 * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler.
 *
 * It deals with calling the driver's FinishAccess() only if necessary.
 */
void
exaFinishAccess(DrawablePtr pDrawable, int index)
{
    ScreenPtr	    pScreen = pDrawable->pScreen;
    ExaScreenPriv  (pScreen);
    PixmapPtr	    pPixmap;
    ExaPixmapPrivPtr pExaPixmap;

    pPixmap = exaGetDrawablePixmap (pDrawable);

    pExaPixmap = ExaGetPixmapPriv(pPixmap);

    /* Rehide pixmap pointer if we're doing that. */
    if (pExaPixmap != NULL && pExaScr->hideOffscreenPixmapData &&
	pExaPixmap->fb_ptr == pPixmap->devPrivate.ptr)
    {
	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
    }

    if (pExaScr->info->FinishAccess == NULL)
	return;

    if (!exaPixmapIsOffscreen (pPixmap))
	return;

    (*pExaScr->info->FinishAccess) (pPixmap, index);
}
Example #5
0
/**
 * exaCreatePixmap() creates a new pixmap.
 *
 * If width and height are 0, this won't be a full-fledged pixmap and it will
 * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
 * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
 * for scratch pixmaps, or to represent the visible screen.
 */
static PixmapPtr
exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth)
{
    PixmapPtr		pPixmap;
    ExaPixmapPrivPtr	pExaPixmap;
    int			bpp;
    ExaScreenPriv(pScreen);

    if (w > 32767 || h > 32767)
	return NullPixmap;

    pPixmap = fbCreatePixmap (pScreen, w, h, depth);
    if (!pPixmap)
	return NULL;
    pExaPixmap = ExaGetPixmapPriv(pPixmap);

    bpp = pPixmap->drawable.bitsPerPixel;

    /* Glyphs have w/h equal to zero, and may not be migrated. See exaGlyphs. */
    if (!w || !h)
	pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
    else
	pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;

    pExaPixmap->area = NULL;

    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
    pExaPixmap->sys_pitch = pPixmap->devKind;

    pExaPixmap->fb_ptr = NULL;
    if (pExaScr->info->flags & EXA_OFFSCREEN_ALIGN_POT && w != 1)
	pExaPixmap->fb_pitch = (1 << (exaLog2(w - 1) + 1)) * bpp / 8;
    else
	pExaPixmap->fb_pitch = w * bpp / 8;
    pExaPixmap->fb_pitch = EXA_ALIGN(pExaPixmap->fb_pitch,
				     pExaScr->info->pixmapPitchAlign);
    pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;

    if (pExaPixmap->fb_pitch > 131071) {
	fbDestroyPixmap(pPixmap);
	return NULL;
    }

    /* Set up damage tracking */
    pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
					pScreen, pPixmap);

    if (pExaPixmap->pDamage == NULL) {
	fbDestroyPixmap (pPixmap);
	return NULL;
    }

    DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
    DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);

    /* None of the pixmap bits are valid initially */
    REGION_NULL(pScreen, &pExaPixmap->validReg);

    return pPixmap;
}
Example #6
0
Bool
exaDestroyPixmap_classic(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;

    ExaScreenPriv(pScreen);
    Bool ret;

    if (pPixmap->refcnt == 1) {
        ExaPixmapPriv(pPixmap);

        exaDestroyPixmap(pPixmap);

        if (pExaPixmap->area) {
            DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
                        (void *) pPixmap->drawable.id,
                        ExaGetPixmapPriv(pPixmap)->area->offset,
                        pPixmap->drawable.width, pPixmap->drawable.height));
            /* Free the offscreen area */
            exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
            pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
            pPixmap->devKind = pExaPixmap->sys_pitch;
        }
        RegionUninit(&pExaPixmap->validSys);
        RegionUninit(&pExaPixmap->validFB);
    }

    swap(pExaScr, pScreen, DestroyPixmap);
    ret = pScreen->DestroyPixmap(pPixmap);
    swap(pExaScr, pScreen, DestroyPixmap);

    return ret;
}
Example #7
0
/**
 * exaGetPixmapSize() returns the size in bytes of the given pixmap in video
 * memory. Only valid when the pixmap is currently in framebuffer.
 */
unsigned long
exaGetPixmapSize(PixmapPtr pPix)
{
    ExaPixmapPrivPtr pExaPixmap;

    pExaPixmap = ExaGetPixmapPriv(pPix);
    if (pExaPixmap != NULL)
	return pExaPixmap->fb_size;
    return 0;
}
Example #8
0
/**
 * Switches the current active location of the pixmap to system memory, copying
 * updated data out if necessary.
 */
void
exaMoveOutPixmap (PixmapPtr pPixmap)
{
    ExaPixmapPriv (pPixmap);

    if (exaPixmapIsPinned(pPixmap))
	return;

    if (exaPixmapIsOffscreen(pPixmap)) {

	DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
		      (void*)(ExaGetPixmapPriv(pPixmap)->area ?
			      ExaGetPixmapPriv(pPixmap)->area->offset : 0),
		      pPixmap->drawable.width,
		      pPixmap->drawable.height,
		      exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));

	exaCopyDirtyToSys (pPixmap);

	pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
	pPixmap->devKind = pExaPixmap->sys_pitch;
	pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
    }
}
Example #9
0
static Bool
exaDestroyPixmap (PixmapPtr pPixmap)
{
    if (pPixmap->refcnt == 1)
    {
	ExaPixmapPriv (pPixmap);
	if (pExaPixmap->area)
	{
	    DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
                        (void*)pPixmap->drawable.id,
			 ExaGetPixmapPriv(pPixmap)->area->offset,
			 pPixmap->drawable.width,
			 pPixmap->drawable.height));
	    /* Free the offscreen area */
	    exaOffscreenFree (pPixmap->drawable.pScreen, pExaPixmap->area);
	    pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
	    pPixmap->devKind = pExaPixmap->sys_pitch;
	}
	REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg);
    }
    return fbDestroyPixmap (pPixmap);
}
Example #10
0
Bool
exaHWCopyNtoN(DrawablePtr pSrcDrawable,
              DrawablePtr pDstDrawable,
              GCPtr pGC,
              BoxPtr pbox,
              int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
{
    ExaScreenPriv(pDstDrawable->pScreen);
    PixmapPtr pSrcPixmap, pDstPixmap;
    ExaPixmapPrivPtr pSrcExaPixmap, pDstExaPixmap;
    int src_off_x, src_off_y;
    int dst_off_x, dst_off_y;
    RegionPtr srcregion = NULL, dstregion = NULL;
    xRectangle *rects;
    Bool ret = TRUE;

    /* avoid doing copy operations if no boxes */
    if (nbox == 0)
        return TRUE;

    pSrcPixmap = exaGetDrawablePixmap(pSrcDrawable);
    pDstPixmap = exaGetDrawablePixmap(pDstDrawable);

    exaGetDrawableDeltas(pSrcDrawable, pSrcPixmap, &src_off_x, &src_off_y);
    exaGetDrawableDeltas(pDstDrawable, pDstPixmap, &dst_off_x, &dst_off_y);

    rects = malloc(nbox * sizeof(xRectangle));

    if (rects) {
        int i;
        int ordering;

        for (i = 0; i < nbox; i++) {
            rects[i].x = pbox[i].x1 + dx + src_off_x;
            rects[i].y = pbox[i].y1 + dy + src_off_y;
            rects[i].width = pbox[i].x2 - pbox[i].x1;
            rects[i].height = pbox[i].y2 - pbox[i].y1;
        }

        /* This must match the RegionCopy() logic for reversing rect order */
        if (nbox == 1 || (dx > 0 && dy > 0) ||
            (pDstDrawable != pSrcDrawable &&
             (pDstDrawable->type != DRAWABLE_WINDOW ||
              pSrcDrawable->type != DRAWABLE_WINDOW)))
            ordering = CT_YXBANDED;
        else
            ordering = CT_UNSORTED;

        srcregion = RegionFromRects(nbox, rects, ordering);
        free(rects);

        if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
                                           pGC->fillStyle, pGC->alu,
                                           pGC->clientClip != NULL)) {
            dstregion = RegionCreate(NullBox, 0);
            RegionCopy(dstregion, srcregion);
            RegionTranslate(dstregion, dst_off_x - dx - src_off_x,
                            dst_off_y - dy - src_off_y);
        }
    }

    pSrcExaPixmap = ExaGetPixmapPriv(pSrcPixmap);
    pDstExaPixmap = ExaGetPixmapPriv(pDstPixmap);

    /* Check whether the accelerator can use this pixmap.
     * If the pitch of the pixmaps is out of range, there's nothing
     * we can do but fall back to software rendering.
     */
    if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
        pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
        goto fallback;

    /* If the width or the height of either of the pixmaps
     * is out of range, check whether the boxes are actually out of the
     * addressable range as well. If they aren't, we can still do
     * the copying in hardware.
     */
    if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
        int i;

        for (i = 0; i < nbox; i++) {
            /* src */
            if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
                (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
                goto fallback;

            /* dst */
            if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
                (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
                goto fallback;
        }
    }

    if (pExaScr->do_migration) {
        ExaMigrationRec pixmaps[2];

        pixmaps[0].as_dst = TRUE;
        pixmaps[0].as_src = FALSE;
        pixmaps[0].pPix = pDstPixmap;
        pixmaps[0].pReg = dstregion;
        pixmaps[1].as_dst = FALSE;
        pixmaps[1].as_src = TRUE;
        pixmaps[1].pPix = pSrcPixmap;
        pixmaps[1].pReg = srcregion;

        exaDoMigration(pixmaps, 2, TRUE);
    }

    /* Mixed directions must be handled specially if the card is lame */
    if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
        reverse != upsidedown) {
        if (exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox,
                              dx, dy))
            goto out;
        goto fallback;
    }

    if (exaPixmapHasGpuCopy(pDstPixmap)) {
        /* Normal blitting. */
        if (exaPixmapHasGpuCopy(pSrcPixmap)) {
            if (!(*pExaScr->info->PrepareCopy)
                (pSrcPixmap, pDstPixmap, reverse ? -1 : 1, upsidedown ? -1 : 1,
                 pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) {
                goto fallback;
            }

            while (nbox--) {
                (*pExaScr->info->Copy) (pDstPixmap,
                                        pbox->x1 + dx + src_off_x,
                                        pbox->y1 + dy + src_off_y,
                                        pbox->x1 + dst_off_x,
                                        pbox->y1 + dst_off_y,
                                        pbox->x2 - pbox->x1,
                                        pbox->y2 - pbox->y1);
                pbox++;
            }

            (*pExaScr->info->DoneCopy) (pDstPixmap);
            exaMarkSync(pDstDrawable->pScreen);
            /* UTS: mainly for SHM PutImage's secondary path.
             *
             * Only taking this path for directly accessible pixmaps.
             */
        }
        else if (!pDstExaPixmap->pDamage && pSrcExaPixmap->sys_ptr) {
            int bpp = pSrcDrawable->bitsPerPixel;
            int src_stride = exaGetPixmapPitch(pSrcPixmap);
            CARD8 *src = NULL;

            if (!pExaScr->info->UploadToScreen)
                goto fallback;

            if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel)
                goto fallback;

            if (pSrcDrawable->bitsPerPixel < 8)
                goto fallback;

            if (pGC &&
                !(pGC->alu == GXcopy &&
                  EXA_PM_IS_SOLID(pSrcDrawable, pGC->planemask)))
                goto fallback;

            while (nbox--) {
                src =
                    pSrcExaPixmap->sys_ptr + (pbox->y1 + dy +
                                              src_off_y) * src_stride +
                    (pbox->x1 + dx + src_off_x) * (bpp / 8);
                if (!pExaScr->info->
                    UploadToScreen(pDstPixmap, pbox->x1 + dst_off_x,
                                   pbox->y1 + dst_off_y, pbox->x2 - pbox->x1,
                                   pbox->y2 - pbox->y1, (char *) src,
                                   src_stride))
                    goto fallback;

                pbox++;
            }
        }
        else
            goto fallback;
    }
    else
        goto fallback;

    goto out;

 fallback:
    ret = FALSE;

 out:
    if (dstregion) {
        RegionUninit(dstregion);
        RegionDestroy(dstregion);
    }
    if (srcregion) {
        RegionUninit(srcregion);
        RegionDestroy(srcregion);
    }

    return ret;
}
Example #11
0
/* Try to do an accelerated tile of the pTile into pRegion of pDrawable.
 * Based on fbFillRegionTiled(), fbTile().
 */
Bool
exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
                   DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
                   Bool hasClientClip)
{
    ExaScreenPriv(pDrawable->pScreen);
    PixmapPtr pPixmap;
    ExaPixmapPrivPtr pExaPixmap;
    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
    int xoff, yoff;
    int tileWidth, tileHeight;
    int nbox = RegionNumRects(pRegion);
    BoxPtr pBox = RegionRects(pRegion);
    Bool ret = FALSE;
    int i;

    tileWidth = pTile->drawable.width;
    tileHeight = pTile->drawable.height;

    /* If we're filling with a solid color, grab it out and go to
     * FillRegionSolid, saving numerous copies.
     */
    if (tileWidth == 1 && tileHeight == 1)
        return exaFillRegionSolid(pDrawable, pRegion,
                                  exaGetPixmapFirstPixel(pTile), planemask,
                                  alu, hasClientClip);

    pPixmap = exaGetDrawablePixmap(pDrawable);
    pExaPixmap = ExaGetPixmapPriv(pPixmap);

    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
        pTileExaPixmap->accel_blocked)
        return FALSE;

    if (pExaScr->do_migration) {
        ExaMigrationRec pixmaps[2];

        pixmaps[0].as_dst = TRUE;
        pixmaps[0].as_src = FALSE;
        pixmaps[0].pPix = pPixmap;
        pixmaps[0].pReg = exaGCReadsDestination(pDrawable, planemask, FillTiled,
                                                alu,
                                                hasClientClip) ? NULL : pRegion;
        pixmaps[1].as_dst = FALSE;
        pixmaps[1].as_src = TRUE;
        pixmaps[1].pPix = pTile;
        pixmaps[1].pReg = NULL;

        exaDoMigration(pixmaps, 2, TRUE);
    }

    pPixmap = exaGetOffscreenPixmap(pDrawable, &xoff, &yoff);

    if (!pPixmap || !exaPixmapHasGpuCopy(pTile))
        return FALSE;

    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask)) {
        if (xoff || yoff)
            RegionTranslate(pRegion, xoff, yoff);

        for (i = 0; i < nbox; i++) {
            int height = pBox[i].y2 - pBox[i].y1;
            int dstY = pBox[i].y1;
            int tileY;

            if (alu == GXcopy)
                height = min(height, tileHeight);

            modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);

            while (height > 0) {
                int width = pBox[i].x2 - pBox[i].x1;
                int dstX = pBox[i].x1;
                int tileX;
                int h = tileHeight - tileY;

                if (alu == GXcopy)
                    width = min(width, tileWidth);

                if (h > height)
                    h = height;
                height -= h;

                modulus(dstX - xoff - pDrawable->x - pPatOrg->x, tileWidth,
                        tileX);

                while (width > 0) {
                    int w = tileWidth - tileX;

                    if (w > width)
                        w = width;
                    width -= w;

                    (*pExaScr->info->Copy) (pPixmap, tileX, tileY, dstX, dstY,
                                            w, h);
                    dstX += w;
                    tileX = 0;
                }
                dstY += h;
                tileY = 0;
            }
        }
        (*pExaScr->info->DoneCopy) (pPixmap);

        /* With GXcopy, we only need to do the basic algorithm up to the tile
         * size; then, we can just keep doubling the destination in each
         * direction until it fills the box. This way, the number of copy
         * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
         * rx/ry is the ratio between box and tile width/height. This can make
         * a big difference if each driver copy incurs a significant constant
         * overhead.
         */
        if (alu != GXcopy)
            ret = TRUE;
        else {
            Bool more_copy = FALSE;

            for (i = 0; i < nbox; i++) {
                int dstX = pBox[i].x1 + tileWidth;
                int dstY = pBox[i].y1 + tileHeight;

                if ((dstX < pBox[i].x2) || (dstY < pBox[i].y2)) {
                    more_copy = TRUE;
                    break;
                }
            }

            if (more_copy == FALSE)
                ret = TRUE;

            if (more_copy && (*pExaScr->info->PrepareCopy) (pPixmap, pPixmap,
                                                            1, 1, alu,
                                                            planemask)) {
                for (i = 0; i < nbox; i++) {
                    int dstX = pBox[i].x1 + tileWidth;
                    int dstY = pBox[i].y1 + tileHeight;
                    int width = min(pBox[i].x2 - dstX, tileWidth);
                    int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);

                    while (dstX < pBox[i].x2) {
                        (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
                                                dstX, pBox[i].y1, width,
                                                height);
                        dstX += width;
                        width = min(pBox[i].x2 - dstX, width * 2);
                    }

                    width = pBox[i].x2 - pBox[i].x1;
                    height = min(pBox[i].y2 - dstY, tileHeight);

                    while (dstY < pBox[i].y2) {
                        (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
                                                pBox[i].x1, dstY, width,
                                                height);
                        dstY += height;
                        height = min(pBox[i].y2 - dstY, height * 2);
                    }
                }

                (*pExaScr->info->DoneCopy) (pPixmap);

                ret = TRUE;
            }
        }

        exaMarkSync(pDrawable->pScreen);

        if (xoff || yoff)
            RegionTranslate(pRegion, -xoff, -yoff);
    }

    return ret;
}
Example #12
0
/**
 * exaCreatePixmap() creates a new pixmap.
 *
 * If width and height are 0, this won't be a full-fledged pixmap and it will
 * get ModifyPixmapHeader() called on it later.  So, we mark it as pinned, because
 * ModifyPixmapHeader() would break migration.  These types of pixmaps are used
 * for scratch pixmaps, or to represent the visible screen.
 */
PixmapPtr
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
                        unsigned usage_hint)
{
    PixmapPtr pPixmap;
    ExaPixmapPrivPtr pExaPixmap;
    BoxRec box;
    int bpp;

    ExaScreenPriv(pScreen);

    if (w > 32767 || h > 32767)
        return NullPixmap;

    swap(pExaScr, pScreen, CreatePixmap);
    pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
    swap(pExaScr, pScreen, CreatePixmap);

    if (!pPixmap)
        return NULL;

    pExaPixmap = ExaGetPixmapPriv(pPixmap);
    pExaPixmap->driverPriv = NULL;

    bpp = pPixmap->drawable.bitsPerPixel;

    pExaPixmap->driverPriv = NULL;
    /* Scratch pixmaps may have w/h equal to zero, and may not be
     * migrated.
     */
    if (!w || !h)
        pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
    else
        pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;

    pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
    pExaPixmap->sys_pitch = pPixmap->devKind;

    pPixmap->devPrivate.ptr = NULL;
    pExaPixmap->use_gpu_copy = FALSE;

    pExaPixmap->fb_ptr = NULL;
    exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
    pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;

    if (pExaPixmap->fb_pitch > 131071) {
        swap(pExaScr, pScreen, DestroyPixmap);
        pScreen->DestroyPixmap(pPixmap);
        swap(pExaScr, pScreen, DestroyPixmap);
        return NULL;
    }

    /* Set up damage tracking */
    pExaPixmap->pDamage = DamageCreate(NULL, NULL,
                                       DamageReportNone, TRUE,
                                       pScreen, pPixmap);

    if (pExaPixmap->pDamage == NULL) {
        swap(pExaScr, pScreen, DestroyPixmap);
        pScreen->DestroyPixmap(pPixmap);
        swap(pExaScr, pScreen, DestroyPixmap);
        return NULL;
    }

    DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
    /* This ensures that pending damage reflects the current operation. */
    /* This is used by exa to optimize migration. */
    DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);

    pExaPixmap->area = NULL;

    /* We set the initial pixmap as completely valid for a simple reason.
     * Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
     * could form single pixel rects as part of a region. Setting the complete region
     * as valid is a natural defragmentation of the region.
     */
    box.x1 = 0;
    box.y1 = 0;
    box.x2 = w;
    box.y2 = h;
    RegionInit(&pExaPixmap->validSys, &box, 0);
    RegionInit(&pExaPixmap->validFB, &box, 0);

    exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);

    /* During a fallback we must prepare access. */
    if (pExaScr->fallback_counter)
        exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);

    return pPixmap;
}
Example #13
0
Bool
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
                              int depth, int bitsPerPixel, int devKind,
                              void *pPixData)
{
    ScreenPtr pScreen;
    ExaScreenPrivPtr pExaScr;
    ExaPixmapPrivPtr pExaPixmap;
    Bool ret;

    if (!pPixmap)
        return FALSE;

    pScreen = pPixmap->drawable.pScreen;
    pExaScr = ExaGetScreenPriv(pScreen);
    pExaPixmap = ExaGetPixmapPriv(pPixmap);

    if (pExaPixmap) {
        if (pPixData)
            pExaPixmap->sys_ptr = pPixData;

        if (devKind > 0)
            pExaPixmap->sys_pitch = devKind;

        /* Classic EXA:
         * - Framebuffer.
         * - Scratch pixmap with gpu memory.
         */
        if (pExaScr->info->memoryBase && pPixData) {
            if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
                ((CARD8 *) pPixData - pExaScr->info->memoryBase) <
                pExaScr->info->memorySize) {
                pExaPixmap->fb_ptr = pPixData;
                pExaPixmap->fb_pitch = devKind;
                pExaPixmap->use_gpu_copy = TRUE;
            }
        }

        if (width > 0 && height > 0 && bitsPerPixel > 0) {
            exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);

            exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
        }

        /* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
         * gpu memory, so there's no need to track damage.
         */
        if (pExaPixmap->pDamage) {
            DamageDestroy(pExaPixmap->pDamage);
            pExaPixmap->pDamage = NULL;
        }
    }

    swap(pExaScr, pScreen, ModifyPixmapHeader);
    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
                                      bitsPerPixel, devKind, pPixData);
    swap(pExaScr, pScreen, ModifyPixmapHeader);

    /* Always NULL this, we don't want lingering pointers. */
    pPixmap->devPrivate.ptr = NULL;

    return ret;
}