示例#1
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);
}
示例#2
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);
}
示例#3
0
/**
 * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
 *
 * It deals with waiting for synchronization with the card, determining if
 * PrepareAccess() is necessary, and working around PrepareAccess() failure.
 */
void
exaPrepareAccess(DrawablePtr pDrawable, int index)
{
    ScreenPtr	    pScreen = pDrawable->pScreen;
    ExaScreenPriv  (pScreen);
    PixmapPtr	    pPixmap;

    pPixmap = exaGetDrawablePixmap (pDrawable);

    if (exaPixmapIsOffscreen (pPixmap))
	exaWaitSync (pDrawable->pScreen);
    else
	return;

    /* Unhide pixmap pointer */
    if (pPixmap->devPrivate.ptr == NULL) {
	ExaPixmapPriv (pPixmap);

	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
    }

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

    if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) {
	ExaPixmapPriv (pPixmap);
	if (pExaPixmap->score != EXA_PIXMAP_SCORE_PINNED)
	    FatalError("Driver failed PrepareAccess on a pinned pixmap\n");
	exaMoveOutPixmap (pPixmap);
    }
}
示例#4
0
/**
 * For the "greedy" migration scheme, pushes the pixmap toward being located in
 * system memory.
 */
static void
exaMigrateTowardSys (PixmapPtr pPixmap)
{
    ExaPixmapPriv (pPixmap);

    if (pExaPixmap == NULL) {
	DBG_MIGRATE(("UseMem: ignoring exa-uncontrolled pixmap %p (%s)\n",
		     (pointer)pPixmap,
		     exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
	return;
    }

    DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));

    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
	return;

    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
	pExaPixmap->score = 0;

    if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
	pExaPixmap->score--;

    if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
	exaMoveOutPixmap (pPixmap);
}
示例#5
0
/**
 * 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.
 */
void
exaMoveInPixmap (PixmapPtr pPixmap)
{
    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 already in FB, our work is done. */
    if (exaPixmapIsOffscreen(pPixmap))
	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->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;
    }

    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'));

    exaCopyDirtyToFb (pPixmap);

    if (pExaScr->hideOffscreenPixmapData)
	pPixmap->devPrivate.ptr = NULL;
    else
	pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
    pPixmap->devKind = pExaPixmap->fb_pitch;
    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
示例#6
0
/**
 * Returns the pixmap which backs a drawable, and the offsets to add to
 * coordinates to make them address the same bits in the backing drawable.
 */
PixmapPtr
exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
{
    PixmapPtr	pPixmap = exaGetDrawablePixmap (pDrawable);

    exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp);

    if (exaPixmapIsOffscreen (pPixmap))
	return pPixmap;
    else
	return NULL;
}
示例#7
0
/**
 * For the "greedy" migration scheme, pushes the pixmap toward being located in
 * framebuffer memory.
 */
static void
exaMigrateTowardFb (PixmapPtr pPixmap)
{
    ExaPixmapPriv (pPixmap);

    if (pExaPixmap == NULL) {
	DBG_MIGRATE(("UseScreen: ignoring exa-uncontrolled pixmap %p (%s)\n",
		     (pointer)pPixmap,
		     exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
	return;
    }

    if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
	DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
		     (pointer)pPixmap));
	return;
    }

    DBG_MIGRATE(("UseScreen %p score %d\n",
		 (pointer)pPixmap, pExaPixmap->score));

    if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
	exaMoveInPixmap(pPixmap);
	pExaPixmap->score = 0;
    }

    if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
	pExaPixmap->score++;

    if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
	!exaPixmapIsOffscreen(pPixmap))
    {
	exaMoveInPixmap (pPixmap);
    }

    ExaOffscreenMarkUsed (pPixmap);
}
示例#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;
    }
}
示例#9
0
/**
 * exaDrawableIsOffscreen() is a convenience wrapper for exaPixmapIsOffscreen().
 */
Bool
exaDrawableIsOffscreen (DrawablePtr pDrawable)
{
    return exaPixmapIsOffscreen (exaGetDrawablePixmap (pDrawable));
}
示例#10
0
/**
 * Performs migration of the pixmaps according to the operation information
 * provided in pixmaps and can_accel and the migration scheme chosen in the
 * config file.
 */
void
exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
    ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
    ExaScreenPriv(pScreen);
    int i, j;

    /* If this debugging flag is set, check each pixmap for whether it is marked
     * as clean, and if so, actually check if that's the case.  This should help
     * catch issues with failing to mark a drawable as dirty.  While it will
     * catch them late (after the operation happened), it at least explains what
     * went wrong, and instrumenting the code to find what operation happened
     * to the pixmap last shouldn't be hard.
     */
    if (pExaScr->checkDirtyCorrectness) {
	for (i = 0; i < npixmaps; i++) {
	    if (!exaPixmapIsDirty (pixmaps[i].pPix) &&
		!exaAssertNotDirty (pixmaps[i].pPix))
		ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
	}
    }
    /* If anything is pinned in system memory, we won't be able to
     * accelerate.
     */
    for (i = 0; i < npixmaps; i++) {
	if (exaPixmapIsPinned (pixmaps[i].pPix) &&
	    !exaPixmapIsOffscreen (pixmaps[i].pPix))
	{
	    EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
		      pixmaps[i].pPix->drawable.width,
		      pixmaps[i].pPix->drawable.height));
	    can_accel = FALSE;
	    break;
	}
    }

    if (pExaScr->migration == ExaMigrationSmart) {
	/* If we've got something as a destination that we shouldn't cause to
	 * become newly dirtied, take the unaccelerated route.
	 */
	for (i = 0; i < npixmaps; i++) {
	    if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
		!exaPixmapIsDirty (pixmaps[i].pPix))
	    {
		for (i = 0; i < npixmaps; i++) {
		    if (!exaPixmapIsDirty (pixmaps[i].pPix))
			exaMoveOutPixmap (pixmaps[i].pPix);
		}
		return;
	    }
	}

	/* If we aren't going to accelerate, then we migrate everybody toward
	 * system memory, and kick out if it's free.
	 */
	if (!can_accel) {
	    for (i = 0; i < npixmaps; i++) {
		exaMigrateTowardSys (pixmaps[i].pPix);
		if (!exaPixmapIsDirty (pixmaps[i].pPix))
		    exaMoveOutPixmap (pixmaps[i].pPix);
	    }
	    return;
	}

	/* Finally, the acceleration path.  Move them all in. */
	for (i = 0; i < npixmaps; i++) {
	    exaMigrateTowardFb(pixmaps[i].pPix);
	    exaMoveInPixmap(pixmaps[i].pPix);
	}
    } else if (pExaScr->migration == ExaMigrationGreedy) {
	/* If we can't accelerate, either because the driver can't or because one of
	 * the pixmaps is pinned in system memory, then we migrate everybody toward
	 * system memory.
	 *
	 * We also migrate toward system if all pixmaps involved are currently in
	 * system memory -- this can mitigate thrashing when there are significantly
	 * more pixmaps active than would fit in memory.
	 *
	 * If not, then we migrate toward FB so that hopefully acceleration can
	 * happen.
	 */
	if (!can_accel) {
	    for (i = 0; i < npixmaps; i++)
		exaMigrateTowardSys (pixmaps[i].pPix);
	    return;
	}

	for (i = 0; i < npixmaps; i++) {
	    if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
		/* Found one in FB, so move all to FB. */
		for (j = 0; j < npixmaps; j++)
		    exaMigrateTowardFb(pixmaps[j].pPix);
		return;
	    }
	}

	/* Nobody's in FB, so move all away from FB. */
	for (i = 0; i < npixmaps; i++)
	    exaMigrateTowardSys(pixmaps[i].pPix);
    } else if (pExaScr->migration == ExaMigrationAlways) {
	/* Always move the pixmaps out if we can't accelerate.  If we can
	 * accelerate, try to move them all in.  If that fails, then move them
	 * back out.
	 */
	if (!can_accel) {
	    for (i = 0; i < npixmaps; i++)
		exaMoveOutPixmap(pixmaps[i].pPix);
	    return;
	}

	/* Now, try to move them all into FB */
	for (i = 0; i < npixmaps; i++) {
	    exaMoveInPixmap(pixmaps[i].pPix);
	    ExaOffscreenMarkUsed (pixmaps[i].pPix);
	}

	/* If we couldn't fit everything in, then kick back out */
	for (i = 0; i < npixmaps; i++) {
	    if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
		EXA_FALLBACK(("Pixmap %p (%dx%d) not in fb\n", pixmaps[i].pPix,
			      pixmaps[i].pPix->drawable.width,
			      pixmaps[i].pPix->drawable.height));
		for (j = 0; j < npixmaps; j++)
		    exaMoveOutPixmap(pixmaps[j].pPix);
		break;
	    }
	}
    }
}
示例#11
0
文件: exa_accel.c 项目: L3oV1nc3/VMGL
static Bool
exaFillRegionSolid (DrawablePtr	pDrawable, RegionPtr pRegion, Pixel pixel,
		    CARD32 planemask, CARD32 alu, unsigned int clientClipType)
{
    ExaScreenPriv(pDrawable->pScreen);
    PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
    ExaPixmapPriv (pPixmap);
    int xoff, yoff;
    Bool ret = FALSE;

    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
    REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);

    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked)
	goto out;

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

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

	exaDoMigration (pixmaps, 1, TRUE);
    }

    if (exaPixmapIsOffscreen (pPixmap) &&
	(*pExaScr->info->PrepareSolid) (pPixmap, alu, planemask, pixel))
    {
	int nbox;
	BoxPtr pBox;

	nbox = REGION_NUM_RECTS (pRegion);
	pBox = REGION_RECTS (pRegion);

	while (nbox--)
	{
	    (*pExaScr->info->Solid) (pPixmap, pBox->x1, pBox->y1, pBox->x2,
				     pBox->y2);
	    pBox++;
	}
	(*pExaScr->info->DoneSolid) (pPixmap);
	exaMarkSync(pDrawable->pScreen);

	if (pExaPixmap->pDamage &&
	    pExaPixmap->sys_ptr && pDrawable->type == DRAWABLE_PIXMAP &&
	    pDrawable->width == 1 && pDrawable->height == 1 &&
	    pDrawable->bitsPerPixel != 24) {
	    ExaPixmapPriv(pPixmap);

	    switch (pDrawable->bitsPerPixel) {
	    case 32:
		*(CARD32*)pExaPixmap->sys_ptr = pixel;
		break;
	    case 16:
		*(CARD16*)pExaPixmap->sys_ptr = pixel;
		break;
	    case 8:
		*(CARD8*)pExaPixmap->sys_ptr = pixel;
	    }

	    REGION_UNION(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
			 pRegion);
	}

	ret = TRUE;
    }

out:
    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);

    return ret;
}
示例#12
0
文件: exa_accel.c 项目: L3oV1nc3/VMGL
static void
exaPolyFillRect(DrawablePtr pDrawable,
		GCPtr	    pGC,
		int	    nrect,
		xRectangle  *prect)
{
    ExaScreenPriv (pDrawable->pScreen);
    RegionPtr	    pClip = fbGetCompositeClip(pGC);
    PixmapPtr	    pPixmap = exaGetDrawablePixmap(pDrawable);
    ExaPixmapPriv (pPixmap);
    register BoxPtr pbox;
    BoxPtr	    pextent;
    int		    extentX1, extentX2, extentY1, extentY2;
    int		    fullX1, fullX2, fullY1, fullY2;
    int		    partX1, partX2, partY1, partY2;
    int		    xoff, yoff;
    int		    xorg, yorg;
    int		    n;
    RegionPtr pReg = RECTS_TO_REGION(pScreen, nrect, prect, CT_UNSORTED);

    /* Compute intersection of rects and clip region */
    REGION_TRANSLATE(pScreen, pReg, pDrawable->x, pDrawable->y);
    REGION_INTERSECT(pScreen, pReg, pClip, pReg);

    if (!REGION_NUM_RECTS(pReg)) {
	goto out;
    }

    exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);

    if (pExaScr->fallback_counter || pExaScr->swappedOut ||
	    pExaPixmap->accel_blocked)
    {
	goto fallback;
    }

    /* For ROPs where overlaps don't matter, convert rectangles to region and
     * call exaFillRegion{Solid,Tiled}.
     */
    if ((pGC->fillStyle == FillSolid || pGC->fillStyle == FillTiled) &&
	(nrect == 1 || pGC->alu == GXcopy || pGC->alu == GXclear ||
	 pGC->alu == GXnoop || pGC->alu == GXcopyInverted ||
	 pGC->alu == GXset)) {
	if (((pGC->fillStyle == FillSolid || pGC->tileIsPixel) &&
	     exaFillRegionSolid(pDrawable, pReg, pGC->fillStyle == FillSolid ?
				pGC->fgPixel : pGC->tile.pixel,	pGC->planemask,
				pGC->alu, pGC->clientClipType)) ||
	    (pGC->fillStyle == FillTiled && !pGC->tileIsPixel &&
	     exaFillRegionTiled(pDrawable, pReg, pGC->tile.pixmap, &pGC->patOrg,
				pGC->planemask, pGC->alu,
				pGC->clientClipType))) {
	    goto out;
	}
    }

    if (pGC->fillStyle != FillSolid &&
	!(pGC->tileIsPixel && pGC->fillStyle == FillTiled))
    {
	goto fallback;
    }

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

	pixmaps[0].as_dst = TRUE;
	pixmaps[0].as_src = FALSE;
	pixmaps[0].pPix = pPixmap;
	pixmaps[0].pReg = NULL;

	exaDoMigration (pixmaps, 1, TRUE);
    }

    if (!exaPixmapIsOffscreen (pPixmap) ||
	!(*pExaScr->info->PrepareSolid) (pPixmap,
					 pGC->alu,
					 pGC->planemask,
					 pGC->fgPixel))
    {
fallback:
	ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect);
	goto out;
    }

    xorg = pDrawable->x;
    yorg = pDrawable->y;

    pextent = REGION_EXTENTS(pGC->pScreen, pClip);
    extentX1 = pextent->x1;
    extentY1 = pextent->y1;
    extentX2 = pextent->x2;
    extentY2 = pextent->y2;
    while (nrect--)
    {
	fullX1 = prect->x + xorg;
	fullY1 = prect->y + yorg;
	fullX2 = fullX1 + (int) prect->width;
	fullY2 = fullY1 + (int) prect->height;
	prect++;

	if (fullX1 < extentX1)
	    fullX1 = extentX1;

	if (fullY1 < extentY1)
	    fullY1 = extentY1;

	if (fullX2 > extentX2)
	    fullX2 = extentX2;

	if (fullY2 > extentY2)
	    fullY2 = extentY2;

	if ((fullX1 >= fullX2) || (fullY1 >= fullY2))
	    continue;
	n = REGION_NUM_RECTS (pClip);
	if (n == 1)
	{
	    (*pExaScr->info->Solid) (pPixmap,
				     fullX1 + xoff, fullY1 + yoff,
				     fullX2 + xoff, fullY2 + yoff);
	}
	else
	{
	    pbox = REGION_RECTS(pClip);
	    /*
	     * clip the rectangle to each box in the clip region
	     * this is logically equivalent to calling Intersect(),
	     * but rectangles may overlap each other here.
	     */
	    while(n--)
	    {
		partX1 = pbox->x1;
		if (partX1 < fullX1)
		    partX1 = fullX1;
		partY1 = pbox->y1;
		if (partY1 < fullY1)
		    partY1 = fullY1;
		partX2 = pbox->x2;
		if (partX2 > fullX2)
		    partX2 = fullX2;
		partY2 = pbox->y2;
		if (partY2 > fullY2)
		    partY2 = fullY2;

		pbox++;

		if (partX1 < partX2 && partY1 < partY2) {
		    (*pExaScr->info->Solid) (pPixmap,
					     partX1 + xoff, partY1 + yoff,
					     partX2 + xoff, partY2 + yoff);
		}
	    }
	}
    }
    (*pExaScr->info->DoneSolid) (pPixmap);
    exaMarkSync(pDrawable->pScreen);

out:
    REGION_UNINIT(pScreen, pReg);
    REGION_DESTROY(pScreen, pReg);
}
示例#13
0
文件: exa_accel.c 项目: L3oV1nc3/VMGL
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 = xalloc(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 miRegionCopy() 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  = RECTS_TO_REGION(pScreen, nbox, rects, ordering);
	xfree(rects);

	if (!pGC || !exaGCReadsDestination(pDstDrawable, pGC->planemask,
					   pGC->fillStyle, pGC->alu,
					   pGC->clientClipType)) {
	    dstregion = REGION_CREATE(pScreen, NullBox, 0);
	    REGION_COPY(pScreen, dstregion, srcregion);
	    REGION_TRANSLATE(pScreen, 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 (exaPixmapIsOffscreen(pDstPixmap)) {
	/* Normal blitting. */
	if (exaPixmapIsOffscreen(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. */
	} else if (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) {
	REGION_UNINIT(pScreen, dstregion);
	REGION_DESTROY(pScreen, dstregion);
    }
    if (srcregion) {
	REGION_UNINIT(pScreen, srcregion);
	REGION_DESTROY(pScreen, srcregion);
    }

    return ret;
}
示例#14
0
文件: exa_accel.c 项目: L3oV1nc3/VMGL
/* 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,
		    unsigned int clientClipType)
{
    ExaScreenPriv(pDrawable->pScreen);
    PixmapPtr pPixmap;
    ExaPixmapPrivPtr pExaPixmap;
    ExaPixmapPrivPtr pTileExaPixmap = ExaGetPixmapPriv(pTile);
    int xoff, yoff;
    int tileWidth, tileHeight;
    int nbox = REGION_NUM_RECTS (pRegion);
    BoxPtr pBox = REGION_RECTS (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, clientClipType);

    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, clientClipType) ? 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 || !exaPixmapIsOffscreen(pTile))
	return FALSE;

    if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
    {
	if (xoff || yoff)
	    REGION_TRANSLATE(pScreen, 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)
	    REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
    }

    return ret;
}