Beispiel #1
0
static Bool
ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
{
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
    modesettingPtr ms = modesettingPTR(pScrn);
    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
    struct exa_context *exa = ms->exa;

    exa_debug_printf("ExaPrepareSolid(0x%x)\n", fg);

    if (!exa->accel)
	return FALSE;

    if (!exa->pipe)
	XORG_FALLBACK("accel not enabled");

    if (!priv || !priv->tex)
	XORG_FALLBACK("%s", !priv ? "!priv" : "!priv->tex");

    if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask))
	XORG_FALLBACK("planeMask is not solid");

    if (alu != GXcopy)
	XORG_FALLBACK("not GXcopy");

    if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
                                        priv->tex->target, 0,
                                        PIPE_BIND_RENDER_TARGET)) {
	XORG_FALLBACK("format %s", util_format_name(priv->tex->format));
    }

    return xorg_solid_bind_state(exa, priv, fg);
}
Beispiel #2
0
static Bool
ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
	       int ydir, int alu, Pixel planeMask)
{
    ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen);
    modesettingPtr ms = modesettingPTR(pScrn);
    struct exa_context *exa = ms->exa;
    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
    struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);

    exa_debug_printf("ExaPrepareCopy\n");

    if (!exa->accel)
	return FALSE;

    if (!exa->pipe)
	XORG_FALLBACK("accel not enabled");

    if (!priv || !priv->tex)
	XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex");

    if (!src_priv || !src_priv->tex)
	XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex");

    if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
	XORG_FALLBACK("planeMask is not solid");

    if (alu != GXcopy)
	XORG_FALLBACK("alu not GXcopy");

    if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
                                        priv->tex->target, 0,
                                        PIPE_BIND_RENDER_TARGET))
	XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format));

    if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format,
                                        src_priv->tex->target, 0,
                                        PIPE_BIND_SAMPLER_VIEW))
	XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format));

    exa->copy.src = src_priv;
    exa->copy.dst = priv;

    return TRUE;
}
Beispiel #3
0
/**
 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
 *
 * This is probably the only case we actually care about.  The rest fall through
 * to migration and fbGetImage, which hopefully will result in migration pushing
 * the pixmap out of framebuffer.
 */
void
exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
            unsigned int format, unsigned long planeMask, char *d)
{
    ExaScreenPriv(pDrawable->pScreen);
    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);

    ExaPixmapPriv(pPix);
    int xoff, yoff;
    Bool ok;

    if (pExaScr->fallback_counter || pExaScr->swappedOut)
        goto fallback;

    /* If there's a system copy, we want to save the result there */
    if (pExaPixmap->pDamage)
        goto fallback;

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

    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
        goto fallback;

    /* Only cover the ZPixmap, solid copy case. */
    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
        goto fallback;

    /* Only try to handle the 8bpp and up cases, since we don't want to think
     * about <8bpp.
     */
    if (pDrawable->bitsPerPixel < 8)
        goto fallback;

    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
                                           pDrawable->y + y + yoff, w, h, d,
                                           PixmapBytePad(w, pDrawable->depth));
    if (ok) {
        exaWaitSync(pDrawable->pScreen);
        return;
    }

 fallback:
    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
}
static Bool checkPVR2DBlt(PixmapPtr pPixmap, int alu, Pixel planemask)
{
	if (alu != GXcopy) {
		DBG("%s: FALSE: (alu != GXcopy)\n", __func__);
		PERF_INCREMENT(fallback_GXcopy);
		return FALSE;
	}

	if (pPixmap->drawable.bitsPerPixel < 8) {
		DBG("%s: FALSE: (pPixmap->drawable.bitsPerPixel < 8)\n",
		    __func__);
		PERF_INCREMENT(fallback_bitsPerPixel);
		return FALSE;
	}

	if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask)) {
		DBG("%s: FALSE: (!EXA_PM_IS_SOLID(&pPixmap->drawable, planemask))\n", __func__);
		PERF_INCREMENT(fallback_isSolid);
		return FALSE;
	}

	return TRUE;
}
Beispiel #5
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;
}
Beispiel #6
0
static Bool
exaDoPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
              int w, int h, int format, char *bits, int src_stride)
{
    ExaScreenPriv(pDrawable->pScreen);
    PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);

    ExaPixmapPriv(pPix);
    RegionPtr pClip;
    BoxPtr pbox;
    int nbox;
    int xoff, yoff;
    int bpp = pDrawable->bitsPerPixel;
    Bool ret = TRUE;

    if (pExaScr->fallback_counter || pExaPixmap->accel_blocked ||
        !pExaScr->info->UploadToScreen)
        return FALSE;

    /* If there's a system copy, we want to save the result there */
    if (pExaPixmap->pDamage)
        return FALSE;

    /* Don't bother with under 8bpp, XYPixmaps. */
    if (format != ZPixmap || bpp < 8)
        return FALSE;

    /* Only accelerate copies: no rop or planemask. */
    if (!EXA_PM_IS_SOLID(pDrawable, pGC->planemask) || pGC->alu != GXcopy)
        return FALSE;

    if (pExaScr->swappedOut)
        return FALSE;

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

        pixmaps[0].as_dst = TRUE;
        pixmaps[0].as_src = FALSE;
        pixmaps[0].pPix = pPix;
        pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);

        exaDoMigration(pixmaps, 1, TRUE);
    }

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

    if (!pPix)
        return FALSE;

    x += pDrawable->x;
    y += pDrawable->y;

    pClip = fbGetCompositeClip(pGC);
    for (nbox = RegionNumRects(pClip),
         pbox = RegionRects(pClip); nbox--; pbox++) {
        int x1 = x;
        int y1 = y;
        int x2 = x + w;
        int y2 = y + h;
        char *src;
        Bool ok;

        if (x1 < pbox->x1)
            x1 = pbox->x1;
        if (y1 < pbox->y1)
            y1 = pbox->y1;
        if (x2 > pbox->x2)
            x2 = pbox->x2;
        if (y2 > pbox->y2)
            y2 = pbox->y2;
        if (x1 >= x2 || y1 >= y2)
            continue;

        src = bits + (y1 - y) * src_stride + (x1 - x) * (bpp / 8);
        ok = pExaScr->info->UploadToScreen(pPix, x1 + xoff, y1 + yoff,
                                           x2 - x1, y2 - y1, src, src_stride);
        /* We have to fall back completely, and ignore what has already been completed.
         * Messing with the fb layer directly like we used to is completely unacceptable.
         */
        if (!ok) {
            ret = FALSE;
            break;
        }
    }

    if (ret)
        exaMarkSync(pDrawable->pScreen);

    return ret;
}
Beispiel #7
0
/**
 * Accelerates GetImage for solid ZPixmap downloads from framebuffer memory.
 *
 * This is probably the only case we actually care about.  The rest fall through
 * to migration and fbGetImage, which hopefully will result in migration pushing
 * the pixmap out of framebuffer.
 */
void
exaGetImage (DrawablePtr pDrawable, int x, int y, int w, int h,
	     unsigned int format, unsigned long planeMask, char *d)
{
    ExaScreenPriv (pDrawable->pScreen);
    PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
    int xoff, yoff;
    Bool ok;

    if (pExaScr->fallback_counter || pExaScr->swappedOut)
	goto fallback;

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

    if (pExaScr->do_migration) {
	BoxRec Box;
	RegionRec Reg;
	ExaMigrationRec pixmaps[1];

	Box.x1 = pDrawable->y + x + xoff;
	Box.y1 = pDrawable->y + y + yoff;
	Box.x2 = Box.x1 + w;
	Box.y2 = Box.y1 + h;

	REGION_INIT(pScreen, &Reg, &Box, 1);

	pixmaps[0].as_dst = FALSE;
	pixmaps[0].as_src = TRUE;
	pixmaps[0].pPix = pPix;
	pixmaps[0].pReg = &Reg;

	exaDoMigration(pixmaps, 1, FALSE);

	REGION_UNINIT(pScreen, &Reg);
    }

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

    if (pPix == NULL || pExaScr->info->DownloadFromScreen == NULL)
	goto fallback;

    /* Only cover the ZPixmap, solid copy case. */
    if (format != ZPixmap || !EXA_PM_IS_SOLID(pDrawable, planeMask))
	goto fallback;

    /* Only try to handle the 8bpp and up cases, since we don't want to think
     * about <8bpp.
     */
    if (pDrawable->bitsPerPixel < 8)
	goto fallback;

    ok = pExaScr->info->DownloadFromScreen(pPix, pDrawable->x + x + xoff,
					   pDrawable->y + y + yoff, w, h, d,
					   PixmapBytePad(w, pDrawable->depth));
    if (ok) {
	exaWaitSync(pDrawable->pScreen);
	return;
    }

fallback:
    ExaCheckGetImage(pDrawable, x, y, w, h, format, planeMask, d);
}
Beispiel #8
0
static Bool
ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
	       int ydir, int alu, Pixel planeMask)
{
    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
    modesettingPtr ms = modesettingPTR(pScrn);
    struct exa_context *exa = ms->exa;
    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
    struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);

    exa_debug_printf("ExaPrepareCopy\n");

    if (!exa->accel)
	return FALSE;

    if (!exa->pipe)
	XORG_FALLBACK("accel not enabled");

    if (!priv || !priv->tex)
	XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex");

    if (!src_priv || !src_priv->tex)
	XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex");

    if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
	XORG_FALLBACK("planeMask is not solid");

    if (alu != GXcopy)
	XORG_FALLBACK("alu not GXcopy");

    if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
                                        priv->tex->target, 0,
                                        PIPE_BIND_RENDER_TARGET))
	XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format));

    if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format,
                                        src_priv->tex->target, 0,
                                        PIPE_BIND_SAMPLER_VIEW))
	XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format));

    exa->copy.src = src_priv;
    exa->copy.dst = priv;

    /* XXX this used to use resource_copy_region for same-surface copies,
     * but they were redefined to not allow overlaps (some of the util code
     * always assumed this anyway).
     * Drivers should implement accelerated resource_copy_region or it will
     * be slow - disable for now.
     */
    if (0 && exa->copy.src != exa->copy.dst) {
       exa->copy.use_surface_copy = TRUE;
    }
    else {
       struct pipe_surface surf_tmpl;
       exa->copy.use_surface_copy = FALSE;

       if (exa->copy.dst == exa->copy.src)
          exa->copy.src_texture = renderer_clone_texture( exa->renderer,
                                                          exa->copy.src->tex );
       else
          pipe_resource_reference(&exa->copy.src_texture,
                                 exa->copy.src->tex);

       memset(&surf_tmpl, 0, sizeof(surf_tmpl));
       u_surface_default_template(&surf_tmpl, exa->copy.dst->tex,
                                  PIPE_BIND_RENDER_TARGET);
       exa->copy.dst_surface =
          exa->pipe->create_surface(exa->pipe,
                                    exa->copy.dst->tex,
                                    &surf_tmpl);


       renderer_copy_prepare(exa->renderer, 
                             exa->copy.dst_surface,
                             exa->copy.src_texture );
    }


    return TRUE;
}
Beispiel #9
0
static Bool
ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
	       int ydir, int alu, Pixel planeMask)
{
    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
    modesettingPtr ms = modesettingPTR(pScrn);
    struct exa_context *exa = ms->exa;
    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
    struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);

#if DEBUG_PRINT
    debug_printf("ExaPrepareCopy\n");
#endif

    if (!exa->accel)
	return FALSE;

    if (!exa->pipe)
	XORG_FALLBACK("accle not enabled");

    if (!priv || !priv->tex)
	XORG_FALLBACK("pDst %s", !priv ? "!priv" : "!priv->tex");

    if (!src_priv || !src_priv->tex)
	XORG_FALLBACK("pSrc %s", !src_priv ? "!priv" : "!priv->tex");

    if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
	XORG_FALLBACK("planeMask is not solid");

    if (alu != GXcopy)
	XORG_FALLBACK("alu not GXcopy");

    if (!exa->scrn->is_format_supported(exa->scrn, priv->tex->format,
                                        priv->tex->target,
                                        PIPE_TEXTURE_USAGE_RENDER_TARGET, 0))
	XORG_FALLBACK("pDst format %s", util_format_name(priv->tex->format));

    if (!exa->scrn->is_format_supported(exa->scrn, src_priv->tex->format,
                                        src_priv->tex->target,
                                        PIPE_TEXTURE_USAGE_SAMPLER, 0))
	XORG_FALLBACK("pSrc format %s", util_format_name(src_priv->tex->format));

    exa->copy.src = src_priv;
    exa->copy.dst = priv;

    /* For same-surface copies, the pipe->surface_copy path is clearly
     * superior, providing it is implemented.  In other cases it's not
     * clear what the better path would be, and eventually we'd
     * probably want to gather timings and choose dynamically.
     */
    if (exa->pipe->surface_copy &&
        exa->copy.src == exa->copy.dst) {

       exa->copy.use_surface_copy = TRUE;
       
       exa->copy.src_surface =
          exa->scrn->get_tex_surface( exa->scrn,
                                      exa->copy.src->tex,
                                      0, 0, 0,
                                      PIPE_BUFFER_USAGE_GPU_READ);

       exa->copy.dst_surface =
          exa->scrn->get_tex_surface( exa->scrn, 
                                      exa->copy.dst->tex,
                                      0, 0, 0, 
                                      PIPE_BUFFER_USAGE_GPU_WRITE );
    }
    else {
       exa->copy.use_surface_copy = FALSE;

       if (exa->copy.dst == exa->copy.src)
          exa->copy.src_texture = renderer_clone_texture( exa->renderer,
                                                          exa->copy.src->tex );
       else
          pipe_texture_reference(&exa->copy.src_texture,
                                 exa->copy.src->tex);

       exa->copy.dst_surface =
          exa->scrn->get_tex_surface(exa->scrn,
                                     exa->copy.dst->tex,
                                     0, 0, 0,
                                     PIPE_BUFFER_USAGE_GPU_WRITE);


       renderer_copy_prepare(exa->renderer, 
                             exa->copy.dst_surface,
                             exa->copy.src_texture );
    }


    return TRUE;
}