/**
 * Creates an appropriate picture for temp mask use.
 */
static PicturePtr
glamor_create_mask_picture(ScreenPtr screen,
                           PicturePtr dst,
                           PictFormatPtr pict_format,
                           CARD16 width, CARD16 height)
{
    PixmapPtr pixmap;
    PicturePtr picture;
    int error;

    if (!pict_format) {
        if (dst->polyEdge == PolyEdgeSharp)
            pict_format = PictureMatchFormat(screen, 1, PICT_a1);
        else
            pict_format = PictureMatchFormat(screen, 8, PICT_a8);
        if (!pict_format)
            return 0;
    }

    pixmap = glamor_create_pixmap(screen, 0, 0,
                                  pict_format->depth,
                                  GLAMOR_CREATE_PIXMAP_CPU);

    if (!pixmap)
        return 0;
    picture = CreatePicture(0, &pixmap->drawable, pict_format,
                            0, 0, serverClient, &error);
    glamor_destroy_pixmap(pixmap);
    return picture;
}
static PixmapPtr
glamor_get_stipple_pixmap(GCPtr gc)
{
    glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    ScreenPtr   screen = gc->pScreen;
    PixmapPtr   bitmap;
    PixmapPtr   pixmap;
    GCPtr       scratch_gc;
    ChangeGCVal changes[2];

    if (gc_priv->stipple)
        return gc_priv->stipple;

    bitmap = gc->stipple;
    if (!bitmap)
        goto bail;

    pixmap = glamor_create_pixmap(screen,
                                  bitmap->drawable.width,
                                  bitmap->drawable.height,
                                  8, GLAMOR_CREATE_NO_LARGE);
    if (!pixmap)
        goto bail;

    scratch_gc = GetScratchGC(8, screen);
    if (!scratch_gc)
        goto bail_pixmap;

    changes[0].val = 0xff;
    changes[1].val = 0x00;
    if (ChangeGC(NullClient, scratch_gc,
                 GCForeground|GCBackground, changes) != Success)
        goto bail_gc;
    ValidateGC(&pixmap->drawable, scratch_gc);

    (*scratch_gc->ops->CopyPlane)(&bitmap->drawable,
                                  &pixmap->drawable,
                                  scratch_gc,
                                  0, 0,
                                  bitmap->drawable.width,
                                  bitmap->drawable.height,
                                  0, 0, 0x1);

    FreeScratchGC(scratch_gc);
    gc_priv->stipple = pixmap;

    glamor_track_stipple(gc);

    return pixmap;

bail_gc:
    FreeScratchGC(scratch_gc);
bail_pixmap:
    glamor_destroy_pixmap(pixmap);
bail:
    return NULL;
}
示例#3
0
/* XXX LARGE pixmap? */
Bool
glamor_fixup_pixmap_priv(ScreenPtr screen, glamor_pixmap_private *pixmap_priv)
{
    glamor_pixmap_fbo *old_fbo;
    glamor_pixmap_fbo *new_fbo = NULL;
    PixmapPtr scratch = NULL;
    glamor_pixmap_private *scratch_priv;
    DrawablePtr drawable;
    GCPtr gc = NULL;
    int ret = FALSE;

    drawable = &pixmap_priv->base.pixmap->drawable;

    if (!GLAMOR_PIXMAP_FBO_NOT_EXACT_SIZE(pixmap_priv))
        return TRUE;

    old_fbo = pixmap_priv->base.fbo;

    if (!old_fbo)
        return FALSE;

    gc = GetScratchGC(drawable->depth, screen);
    if (!gc)
        goto fail;

    scratch = glamor_create_pixmap(screen, drawable->width, drawable->height,
                                   drawable->depth, GLAMOR_CREATE_PIXMAP_FIXUP);

    scratch_priv = glamor_get_pixmap_private(scratch);

    if (!scratch_priv->base.fbo)
        goto fail;

    ValidateGC(&scratch->drawable, gc);
    glamor_copy_area(drawable,
                     &scratch->drawable,
                     gc, 0, 0, drawable->width, drawable->height, 0, 0);
    old_fbo = glamor_pixmap_detach_fbo(pixmap_priv);
    new_fbo = glamor_pixmap_detach_fbo(scratch_priv);
    glamor_pixmap_attach_fbo(pixmap_priv->base.pixmap, new_fbo);
    glamor_pixmap_attach_fbo(scratch, old_fbo);

    DEBUGF("old %dx%d type %d\n",
           drawable->width, drawable->height, pixmap_priv->type);
    DEBUGF("copy tex %d  %dx%d to tex %d %dx%d \n",
           old_fbo->tex, old_fbo->width, old_fbo->height, new_fbo->tex,
           new_fbo->width, new_fbo->height);
    ret = TRUE;
 fail:
    if (gc)
        FreeScratchGC(gc);
    if (scratch)
        glamor_destroy_pixmap(scratch);

    return ret;
}
示例#4
0
static PixmapPtr
glamor_get_dash_pixmap(GCPtr gc)
{
    glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
    ScreenPtr   screen = gc->pScreen;
    PixmapPtr   pixmap;
    int         offset;
    int         d;
    uint32_t    pixel;
    GCPtr       scratch_gc;

    if (gc_priv->dash)
        return gc_priv->dash;

    offset = 0;
    for (d = 0; d < gc->numInDashList; d++)
        offset += gc->dash[d];

    pixmap = glamor_create_pixmap(screen, offset, 1, 8, 0);
    if (!pixmap)
        goto bail;

    scratch_gc = GetScratchGC(8, screen);
    if (!scratch_gc)
        goto bail_pixmap;

    pixel = 0xffffffff;
    offset = 0;
    for (d = 0; d < gc->numInDashList; d++) {
        xRectangle      rect;
        ChangeGCVal     changes;

        changes.val = pixel;
        (void) ChangeGC(NullClient, scratch_gc,
                        GCForeground, &changes);
        ValidateGC(&pixmap->drawable, scratch_gc);
        rect.x = offset;
        rect.y = 0;
        rect.width = gc->dash[d];
        rect.height = 1;
        scratch_gc->ops->PolyFillRect (&pixmap->drawable, scratch_gc, 1, &rect);
        offset += gc->dash[d];
        pixel = ~pixel;
    }
    FreeScratchGC(scratch_gc);

    gc_priv->dash = pixmap;
    return pixmap;

bail_pixmap:
    glamor_destroy_pixmap(pixmap);
bail:
    return NULL;
}
示例#5
0
static Bool
xwl_glamor_destroy_pixmap(PixmapPtr pixmap)
{
    struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen);
    struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);

    if (xwl_pixmap && pixmap->refcnt == 1) {
        if (xwl_pixmap->buffer)
            wl_buffer_destroy(xwl_pixmap->buffer);

        eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image);
        gbm_bo_destroy(xwl_pixmap->bo);
        free(xwl_pixmap);
    }

    return glamor_destroy_pixmap(pixmap);
}
示例#6
0
static Bool 
_glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
		 int w, int h, int left_pad, int image_format, char *bits, Bool fallback)
{
	PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
	glamor_pixmap_private *pixmap_priv =
	    glamor_get_pixmap_private(pixmap);
	RegionPtr clip;
	int x_off, y_off;
	Bool ret = FALSE;
	PixmapPtr temp_pixmap, sub_pixmap;
	glamor_pixmap_private *temp_pixmap_priv;
	BoxRec box;
	int stride;

	glamor_get_drawable_deltas(drawable, pixmap, &x_off, &y_off);
	clip = fbGetCompositeClip(gc);
	if (image_format == XYBitmap) {
		assert(depth == 1);
		goto fail;
	}

	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) {
		glamor_fallback("has no fbo.\n");
		goto fail;
	}

	if (image_format != ZPixmap) {
		glamor_fallback("non-ZPixmap\n");
		goto fail;
	}

	if (!glamor_set_planemask(pixmap, gc->planemask)) {
		goto fail;
	}
	/* create a temporary pixmap and upload the bits to that
	 * pixmap, then apply clip copy it to the destination pixmap.*/
	stride = PixmapBytePad(w, depth);
	box.x1 = x + drawable->x;
	box.y1 = y + drawable->y;
	box.x2 = x + w + drawable->x;
	box.y2 = y + h + drawable->y;

	if ((clip != NULL && RegionContainsRect(clip, &box) != rgnIN)
	     || gc->alu != GXcopy) {
		temp_pixmap = glamor_create_pixmap(drawable->pScreen, w, h, depth, 0);
		if (temp_pixmap == NULL)
			goto fail;

		temp_pixmap_priv = glamor_get_pixmap_private(temp_pixmap);

		if (GLAMOR_PIXMAP_PRIV_IS_PICTURE(pixmap_priv)) {
			temp_pixmap_priv->base.picture = pixmap_priv->base.picture;
			temp_pixmap_priv->base.is_picture = pixmap_priv->base.is_picture;
		}

		glamor_upload_sub_pixmap_to_texture(temp_pixmap, 0, 0, w, h,
		                                    stride, bits, 0);
		glamor_copy_area(&temp_pixmap->drawable, drawable, gc, 0, 0, w, h, x, y);
		glamor_destroy_pixmap(temp_pixmap);
	} else {
		glamor_upload_sub_pixmap_to_texture(pixmap, x + drawable->x + x_off, y + drawable->y + y_off,
		                                    w, h, stride, bits, 0);
	}
	ret = TRUE;
	goto done;

fail:
	glamor_set_planemask(pixmap, ~0);

	if (!fallback
	    && glamor_ddx_fallback_check_pixmap(&pixmap->drawable))
		goto done;

	glamor_fallback("to %p (%c)\n",
			drawable, glamor_get_drawable_location(drawable));

	sub_pixmap = glamor_get_sub_pixmap(pixmap, x + x_off + drawable->x,
					   y + y_off + drawable->y, w, h,
					   GLAMOR_ACCESS_RW);
	if (sub_pixmap) {
		if (clip != NULL)
			pixman_region_translate (clip, -x - drawable->x, -y - drawable->y);

		fbPutImage(&sub_pixmap->drawable, gc, depth, 0, 0, w, h,
			   left_pad, image_format, bits);

		glamor_put_sub_pixmap(sub_pixmap, pixmap,
				      x + x_off + drawable->x,
				      y + y_off + drawable->y,
				      w, h, GLAMOR_ACCESS_RW);
		if (clip != NULL)
			pixman_region_translate (clip, x + drawable->x, y + drawable->y);
	} else
		fbPutImage(drawable, gc, depth, x, y, w, h,
			   left_pad, image_format, bits);
	ret = TRUE;

done:
	return ret;
}
static inline void
glamor_copy_glyph(PixmapPtr     glyph_pixmap,
                  DrawablePtr   atlas_draw,
                  int16_t x,
                  int16_t y)
{
    DrawablePtr glyph_draw = &glyph_pixmap->drawable;
    BoxRec      box = {
        .x1 = 0,
        .y1 = 0,
        .x2 = glyph_draw->width,
        .y2 = glyph_draw->height,
    };
    PixmapPtr upload_pixmap = glyph_pixmap;

    if (glyph_pixmap->drawable.bitsPerPixel != atlas_draw->bitsPerPixel) {

        /* If we're dealing with 1-bit glyphs, we copy them to a
         * temporary 8-bit pixmap and upload them from there, since
         * that's what GL can handle.
         */
        ScreenPtr       screen = atlas_draw->pScreen;
        GCPtr           scratch_gc;
        ChangeGCVal     changes[2];

        upload_pixmap = glamor_create_pixmap(screen,
                                             glyph_draw->width,
                                             glyph_draw->height,
                                             atlas_draw->depth,
                                             GLAMOR_CREATE_PIXMAP_CPU);
        if (!upload_pixmap)
            return;

        scratch_gc = GetScratchGC(upload_pixmap->drawable.depth, screen);
        if (!scratch_gc) {
            glamor_destroy_pixmap(upload_pixmap);
            return;
        }
        changes[0].val = 0xff;
        changes[1].val = 0x00;
        if (ChangeGC(NullClient, scratch_gc,
                     GCForeground|GCBackground, changes) != Success) {
            glamor_destroy_pixmap(upload_pixmap);
            FreeScratchGC(scratch_gc);
            return;
        }
        ValidateGC(&upload_pixmap->drawable, scratch_gc);

        (*scratch_gc->ops->CopyPlane)(glyph_draw,
                                      &upload_pixmap->drawable,
                                      scratch_gc,
                                      0, 0,
                                      glyph_draw->width,
                                      glyph_draw->height,
                                      0, 0, 0x1);
    }
    glamor_upload_boxes((PixmapPtr) atlas_draw,
                        &box, 1,
                        0, 0,
                        x, y,
                        upload_pixmap->devPrivate.ptr,
                        upload_pixmap->devKind);

    if (upload_pixmap != glyph_pixmap)
        glamor_destroy_pixmap(upload_pixmap);
}

static Bool
glamor_glyph_atlas_init(ScreenPtr screen, struct glamor_glyph_atlas *atlas)
{
    glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
    PictFormatPtr               format = atlas->format;

    atlas->atlas = glamor_create_pixmap(screen, glamor_priv->glyph_atlas_dim,
                                        glamor_priv->glyph_atlas_dim, format->depth,
                                        GLAMOR_CREATE_FBO_NO_FBO);
    if (!glamor_pixmap_has_fbo(atlas->atlas)) {
        glamor_destroy_pixmap(atlas->atlas);
        atlas->atlas = NULL;
    }
    atlas->x = 0;
    atlas->y = 0;
    atlas->row_height = 0;
    atlas->serial++;
    atlas->nglyph = 0;
    return TRUE;
}
示例#8
0
static Bool
_glamor_copy_n_to_n(DrawablePtr src,
		    DrawablePtr dst,
		    GCPtr gc,
		    BoxPtr box,
		    int nbox,
		    int dx,
		    int dy,
		    Bool reverse,
		    Bool upsidedown, Pixel bitplane,
		    void *closure, Bool fallback)
{
	PixmapPtr dst_pixmap, src_pixmap;
	glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
	glamor_screen_private *glamor_priv;
	glamor_gl_dispatch *dispatch;
	BoxPtr extent;
	RegionRec region;
	int src_x_off, src_y_off, dst_x_off, dst_y_off;
	Bool ok = FALSE;
	int force_clip = 0;

	if (nbox == 0)
		return TRUE;
	dst_pixmap = glamor_get_drawable_pixmap(dst);
	dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
	src_pixmap = glamor_get_drawable_pixmap(src);
	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);

	glamor_priv = glamor_get_screen_private(dst->pScreen);

	DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
		box[0].x1, box[0].y1,
		box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
		dx, dy,
		src_pixmap, dst_pixmap);

	if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_pixmap_priv))
		goto fall_back;

	if (gc) {
		if (!glamor_set_planemask(dst_pixmap, gc->planemask))
			goto fall_back;
		dispatch = glamor_get_dispatch(glamor_priv);
		if (!glamor_set_alu(dispatch, gc->alu)) {
			glamor_put_dispatch(glamor_priv);
			goto fail_noregion;
		}
		glamor_put_dispatch(glamor_priv);
	}

	if (!src_pixmap_priv) {
		glamor_set_pixmap_type(src_pixmap, GLAMOR_MEMORY);
		src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
	}

	glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
				   &src_y_off);
	glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
				   &dst_y_off);

	RegionInitBoxes(&region, box, nbox);
	extent = RegionExtents(&region);

	if (!glamor_check_fbo_size(glamor_priv,
		extent->x2 - extent->x1, extent->y2 - extent->y1)
	   && (src_pixmap_priv->type == GLAMOR_MEMORY
		|| (src_pixmap_priv == dst_pixmap_priv))) {
		force_clip = 1;
	}

	if (force_clip || dst_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
	    || src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
			glamor_pixmap_clipped_regions *clipped_dst_regions;
			int n_dst_region, i, j;
			PixmapPtr temp_source_pixmap;
			glamor_pixmap_private *temp_source_priv = NULL;

			RegionTranslate(&region, dst_x_off, dst_y_off);
			if (!force_clip)
				clipped_dst_regions = glamor_compute_clipped_regions(dst_pixmap_priv,
										     &region, &n_dst_region, 0,
										     reverse, upsidedown);
			else
				clipped_dst_regions = glamor_compute_clipped_regions_ext(dst_pixmap_priv,
										         &region, &n_dst_region,
											 glamor_priv->max_fbo_size,
											 glamor_priv->max_fbo_size,
											 reverse, upsidedown);
			for(i = 0; i < n_dst_region; i++)
			{
				int n_src_region;
				glamor_pixmap_clipped_regions *clipped_src_regions;
				BoxPtr current_boxes;
				int n_current_boxes;

				SET_PIXMAP_FBO_CURRENT(dst_pixmap_priv, clipped_dst_regions[i].block_idx);

				temp_source_pixmap = NULL;
				if (src_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
					RegionTranslate(clipped_dst_regions[i].region,
							-dst_x_off + src_x_off + dx, -dst_y_off + src_y_off + dy);
					clipped_src_regions = glamor_compute_clipped_regions(src_pixmap_priv,
											     clipped_dst_regions[i].region,
											     &n_src_region, 0,
											     reverse, upsidedown);
					DEBUGF("Source is large pixmap.\n");
					for (j = 0; j < n_src_region; j++)
					{
						if (src_pixmap_priv != dst_pixmap_priv)
							SET_PIXMAP_FBO_CURRENT(src_pixmap_priv, clipped_src_regions[j].block_idx);
						else if (src_pixmap_priv == dst_pixmap_priv &&
						    clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx) {
							/* source and the dest are the same, but need different block_idx.
							 * we create a empty pixmap and fill the required source fbo and box to
							 * it. It's a little hacky, but avoid extra copy. */
							temp_source_pixmap = glamor_create_pixmap(src->pScreen, 0, 0,
												  src->depth, 0);
							if (!temp_source_pixmap) {
								ok = FALSE;
								goto fail;
							}
							src->pScreen->ModifyPixmapHeader(temp_source_pixmap,
										      src_pixmap->drawable.width,
										      src_pixmap->drawable.height,
										      0, 0, src_pixmap->devKind, NULL);
							temp_source_priv = glamor_get_pixmap_private(temp_source_pixmap);
							*temp_source_priv = *src_pixmap_priv;
							temp_source_priv->large.box = src_pixmap_priv->large.box_array[clipped_src_regions[j].block_idx];
							temp_source_priv->base.fbo = src_pixmap_priv->large.fbo_array[clipped_src_regions[j].block_idx];
							temp_source_priv->base.pixmap = temp_source_pixmap;
						}
						assert(temp_source_pixmap || !(src_pixmap_priv == dst_pixmap_priv
							&& (clipped_src_regions[j].block_idx != clipped_dst_regions[i].block_idx)));

						RegionTranslate(clipped_src_regions[j].region,
								-src_x_off - dx,
								-src_y_off - dy);
						current_boxes = RegionRects(clipped_src_regions[j].region);
						n_current_boxes = RegionNumRects(clipped_src_regions[j].region);
						DEBUGF("dst pixmap fbo idx %d src pixmap fbo idx %d \n",
							clipped_dst_regions[i].block_idx,
							clipped_src_regions[j].block_idx);
						DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
							current_boxes[0].x1, current_boxes[0].y1,
							current_boxes[0].x2, current_boxes[0].y2,
							dx, dy, src_pixmap, dst_pixmap);
						if (!temp_source_pixmap)
							ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
										  n_current_boxes, dx, dy, reverse,
										  upsidedown, bitplane, closure);
						else {
							ok = __glamor_copy_n_to_n(&temp_source_pixmap->drawable,
										  dst, gc, current_boxes,
										  n_current_boxes, dx, dy, reverse,
										  upsidedown, bitplane, closure);
							temp_source_priv->type = GLAMOR_MEMORY;
							temp_source_priv->base.fbo = NULL;
							glamor_destroy_pixmap(temp_source_pixmap);
							temp_source_pixmap = NULL;
						}

						RegionDestroy(clipped_src_regions[j].region);
						if (!ok) {
							assert(0);
							goto fail;
						}
					}

					if (n_src_region == 0)
						ok = TRUE;
					free(clipped_src_regions);
				} else {
					RegionTranslate(clipped_dst_regions[i].region,
							- dst_x_off,
							- dst_y_off);
					current_boxes = RegionRects(clipped_dst_regions[i].region);
					n_current_boxes = RegionNumRects(clipped_dst_regions[i].region);

						DEBUGF("dest pixmap fbo idx %d \n",
							clipped_dst_regions[i].block_idx);
						DEBUGF("Copy %d %d %d %d dx %d dy %d from %p to %p \n",
							current_boxes[0].x1, current_boxes[0].y1,
							current_boxes[0].x2, current_boxes[0].y2,
							dx, dy, src_pixmap, dst_pixmap);

					ok = __glamor_copy_n_to_n(src, dst, gc, current_boxes,
								  n_current_boxes, dx, dy, reverse,
								  upsidedown, bitplane, closure);

				}
				RegionDestroy(clipped_dst_regions[i].region);
			}
		if (n_dst_region == 0)
			ok = TRUE;
		free(clipped_dst_regions);
	} else {
		ok = __glamor_copy_n_to_n(src, dst, gc, box, nbox, dx, dy,
					  reverse, upsidedown, bitplane,
					  closure);
	}

fail:
	RegionUninit(&region);
fail_noregion:
	dispatch = glamor_get_dispatch(glamor_priv);
	glamor_set_alu(dispatch, GXcopy);
	glamor_put_dispatch(glamor_priv);

	if (ok)
		return TRUE;
fall_back:
	if (!fallback
	    && glamor_ddx_fallback_check_pixmap(src)
	    && glamor_ddx_fallback_check_pixmap(dst))
		goto done;

	if (src_pixmap_priv->type == GLAMOR_DRM_ONLY
	    || dst_pixmap_priv->type == GLAMOR_DRM_ONLY) {
		LogMessage(X_WARNING,
			   "Access a DRM only pixmap is not allowed within glamor.\n");
		return TRUE;
	}
	glamor_report_delayed_fallbacks(src->pScreen);
	glamor_report_delayed_fallbacks(dst->pScreen);

	glamor_fallback("from %p to %p (%c,%c)\n", src, dst,
			glamor_get_drawable_location(src),
			glamor_get_drawable_location(dst));

	if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) &&
	    glamor_prepare_access(src, GLAMOR_ACCESS_RO) &&
	    glamor_prepare_access_gc(gc)) {
		fbCopyNtoN(src, dst, gc, box, nbox,
			   dx, dy, reverse, upsidedown, bitplane, closure);
	}
	glamor_finish_access_gc(gc);
	glamor_finish_access(src);
	glamor_finish_access(dst);
	ok = TRUE;

      done:
	glamor_clear_delayed_fallbacks(src->pScreen);
	glamor_clear_delayed_fallbacks(dst->pScreen);
	return ok;
}
示例#9
0
static Bool
__glamor_copy_n_to_n(DrawablePtr src,
		     DrawablePtr dst,
		     GCPtr gc,
		     BoxPtr box,
		     int nbox,
		     int dx,
		     int dy,
		     Bool reverse,
		     Bool upsidedown, Pixel bitplane,
		     void *closure)
{
	PixmapPtr dst_pixmap, src_pixmap, temp_pixmap = NULL;
	DrawablePtr temp_src = src;
	glamor_pixmap_private *dst_pixmap_priv, *src_pixmap_priv;
	glamor_screen_private *glamor_priv;
	BoxRec bound;
	ScreenPtr screen;
	int temp_dx = dx;
	int temp_dy = dy;
	int src_x_off, src_y_off, dst_x_off, dst_y_off;
	int i;
	int overlaped = 0;
	Bool ret = FALSE;

	dst_pixmap = glamor_get_drawable_pixmap(dst);
	dst_pixmap_priv = glamor_get_pixmap_private(dst_pixmap);
	src_pixmap = glamor_get_drawable_pixmap(src);
	src_pixmap_priv = glamor_get_pixmap_private(src_pixmap);
	screen = dst_pixmap->drawable.pScreen;
	glamor_priv = glamor_get_screen_private(dst->pScreen);
	glamor_get_drawable_deltas(src, src_pixmap, &src_x_off,
				   &src_y_off);

	glamor_get_drawable_deltas(dst, dst_pixmap, &dst_x_off,
				   &dst_y_off);

	if (src_pixmap_priv->base.fbo
		&& src_pixmap_priv->base.fbo->fb == dst_pixmap_priv->base.fbo->fb) {
		int x_shift = abs(src_x_off - dx - dst_x_off);
		int y_shift = abs(src_y_off - dy - dst_y_off);
		for (i = 0; i < nbox; i++) {
			if (x_shift < abs(box[i].x2 - box[i].x1)
			    && y_shift < abs(box[i].y2 - box[i].y1)) {
				overlaped = 1;
				break;
			}
		}
	}
	DEBUGF("Copy %d %d %dx%d dx %d dy %d from %p to %p \n",
		box[0].x1, box[0].y1,
		box[0].x2 - box[0].x1, box[0].y2 - box[0].y1,
		dx, dy,
		src_pixmap, dst_pixmap);
#ifndef GLAMOR_GLES2
	if (!overlaped &&
	    (glamor_priv->state != RENDER_STATE
	     || !src_pixmap_priv->base.gl_tex || !dst_pixmap_priv->base.gl_tex)
	    && glamor_copy_n_to_n_fbo_blit(src, dst, gc, box, nbox, dx,
					   dy)) {
		ret = TRUE;
		goto done;
	}
#endif
	glamor_calculate_boxes_bound(&bound, box, nbox);

	/*  Overlaped indicate the src and dst are the same pixmap. */
	if (overlaped || (!GLAMOR_PIXMAP_PRIV_HAS_FBO(src_pixmap_priv)
			  && (((bound.x2 - bound.x1) * (bound.y2 - bound.y1)
			      * 4 >
			      src_pixmap->drawable.width *
			      src_pixmap->drawable.height)
				|| !(glamor_check_fbo_size(glamor_priv,
					src_pixmap->drawable.width,
					src_pixmap->drawable.height))))) {

		temp_pixmap = glamor_create_pixmap(screen,
						   bound.x2 - bound.x1,
						   bound.y2 - bound.y1,
						   src_pixmap->
						   drawable.depth,
						   overlaped ? 0 :
						   GLAMOR_CREATE_PIXMAP_CPU);
		assert(bound.x2 - bound.x1 <= glamor_priv->max_fbo_size);
		assert(bound.y2 - bound.y1 <= glamor_priv->max_fbo_size);
		if (!temp_pixmap)
			goto done;
		glamor_translate_boxes(box, nbox, -bound.x1, -bound.y1);
		temp_src = &temp_pixmap->drawable;

		if (overlaped)
			glamor_copy_n_to_n_textured(src, temp_src, gc, box,
						    nbox,
						    temp_dx + bound.x1,
						    temp_dy + bound.y1);
		else
			fbCopyNtoN(src, temp_src, gc, box, nbox,
				   temp_dx + bound.x1, temp_dy + bound.y1,
				   reverse, upsidedown, bitplane, closure);
		glamor_translate_boxes(box, nbox, bound.x1, bound.y1);
		temp_dx = -bound.x1;
		temp_dy = -bound.y1;
	} else {
		temp_dx = dx;
		temp_dy = dy;
		temp_src = src;
	}

	if (glamor_copy_n_to_n_textured
	    (temp_src, dst, gc, box, nbox, temp_dx, temp_dy)) {
		ret = TRUE;
	}
done:
	if (temp_src != src)
		glamor_destroy_pixmap(temp_pixmap);
	return ret;
}