static inline Bool
canexchange(DrawablePtr pDraw, struct armsoc_bo *src_bo, struct armsoc_bo *dst_bo)
{
	Bool ret = FALSE;
	ScreenPtr pScreen = pDraw->pScreen;
	PixmapPtr pRootPixmap, pWindowPixmap;
	int src_fb_id, dst_fb_id;

	pRootPixmap = pScreen->GetWindowPixmap(pScreen->root);
	pWindowPixmap = pDraw->type == DRAWABLE_PIXMAP ? (PixmapPtr)pDraw : pScreen->GetWindowPixmap((WindowPtr)pDraw);

	src_fb_id = armsoc_bo_get_fb(src_bo);
	dst_fb_id = armsoc_bo_get_fb(dst_bo);

	if (pRootPixmap != pWindowPixmap &&
	    armsoc_bo_width(src_bo) == armsoc_bo_width(dst_bo) &&
	    armsoc_bo_height(src_bo) == armsoc_bo_height(dst_bo) &&
	    armsoc_bo_bpp(src_bo) == armsoc_bo_bpp(dst_bo) &&
	    armsoc_bo_width(src_bo) == pDraw->width &&
	    armsoc_bo_height(src_bo) == pDraw->height &&
	    armsoc_bo_bpp(src_bo) == pDraw->bitsPerPixel &&
	    src_fb_id == 0 && dst_fb_id == 0) {
		ret = TRUE;
	}

	return ret;
}
static void
ARMSOCDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
		DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
{
	ScreenPtr pScreen = pDraw->pScreen;
	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
	RegionPtr pCopyClip;
	GCPtr pGC;
        PixmapPtr pScratchPixmap;
        struct ARMSOCDRI2BufferRec *src = ARMSOCBUF(pSrcBuffer);

	DEBUG_MSG("pDraw=%p, pDstBuffer=%p pSrcBuffer=%p",
			pDraw, pDstBuffer, pSrcBuffer);

	pGC = GetScratchGC(pDraw->depth, pScreen);
	if (!pGC)
		return;

	pCopyClip = REGION_CREATE(pScreen, NULL, 0);
	RegionCopy(pCopyClip, pRegion);
	(*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0);
	ValidateGC(pDraw, pGC);

	/* If the dst is the framebuffer, and we had a way to
	 * schedule a deferred blit synchronized w/ vsync, that
	 * would be a nice thing to do utilize here to avoid
	 * tearing..  when we have sync object support for GEM
	 * buffers, I think we could do something more clever
	 * here.
	 */

        pScratchPixmap = GetScratchPixmapHeader(pScreen,
		armsoc_bo_width(src->bo), armsoc_bo_height(src->bo),
		armsoc_bo_depth(src->bo), armsoc_bo_bpp(src->bo),
		armsoc_bo_pitch(src->bo), armsoc_bo_map(src->bo));
		

	pGC->ops->CopyArea((DrawablePtr) pScratchPixmap, pDraw, pGC,
			0, 0, pDraw->width, pDraw->height, 0, 0);
	FreeScratchPixmapHeader(pScratchPixmap);
	FreeScratchGC(pGC);
}
/**
 * Create Buffer.
 *
 * Note that 'format' is used from the client side to specify the DRI buffer
 * format, which could differ from the drawable format.  For example, the
 * drawable could be 32b RGB, but the DRI buffer some YUV format (video) or
 * perhaps lower bit depth RGB (GL).  The color conversion is handled when
 * blitting to front buffer, and page-flipping (overlay or flipchain) can
 * only be used if the display supports.
 */
static DRI2BufferPtr
ARMSOCDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
		unsigned int format)
{
	ScreenPtr pScreen = pDraw->pScreen;
	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
	struct ARMSOCDRI2BufferRec *buf = calloc(1, sizeof(*buf));
	struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
	struct armsoc_bo *bo;

	DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x",
			pDraw, attachment, format);

	if (!buf) {
		ERROR_MSG("Couldn't allocate internal buffer structure");
		return NULL;
	}

	buf->refcnt = 1;
	buf->previous_canflip = canflip(pDraw);
	DRIBUF(buf)->attachment = attachment;
	DRIBUF(buf)->cpp = pDraw->bitsPerPixel / 8;
	DRIBUF(buf)->format = format + 1; /* suppress DRI2 buffer reuse */
	DRIBUF(buf)->flags = 0;

	/* If it is a pixmap, just migrate to a GEM buffer */
	if (pDraw->type == DRAWABLE_PIXMAP)
	{
	    if (!(bo = MigratePixmapToGEM(pARMSOC, pDraw))) {
	        ErrorF("ARMSOCDRI2CreateBuffer: MigratePixmapToUMP failed\n");
	        free(buf);
	        return NULL;
	    }
	    DRIBUF(buf)->pitch = armsoc_bo_pitch(bo);
	    DRIBUF(buf)->name = armsoc_bo_name(bo);
            buf->bo = bo;
	    return DRIBUF(buf);
	}

	/* We are not interested in anything other than back buffer requests ... */
	if (attachment != DRI2BufferBackLeft || pDraw->type != DRAWABLE_WINDOW) {
		/* ... and just return some dummy UMP buffer */
		bo = pARMSOC->scanout;
		DRIBUF(buf)->pitch = armsoc_bo_pitch(bo);
		DRIBUF(buf)->name = armsoc_bo_name(bo);
		buf->bo = bo;
		armsoc_bo_reference(bo);
		return DRIBUF(buf);
	}

	bo = armsoc_bo_from_drawable(pDraw);
	if (bo && armsoc_bo_width(bo) == pDraw->width && armsoc_bo_height(bo) == pDraw->height && armsoc_bo_bpp(bo) == pDraw->bitsPerPixel) {
		// Reuse existing
		DRIBUF(buf)->pitch = armsoc_bo_pitch(bo);
		DRIBUF(buf)->name = armsoc_bo_name(bo);
		buf->bo = bo;
		armsoc_bo_reference(bo);
		return DRIBUF(buf);
	}

	bo = armsoc_bo_new_with_dim(pARMSOC->dev,
                                pDraw->width,
                                pDraw->height,
                                pDraw->depth,
                                pDraw->bitsPerPixel,
				canflip(pDraw) ? ARMSOC_BO_SCANOUT : ARMSOC_BO_NON_SCANOUT);
	if (!bo) {
	        ErrorF("ARMSOCDRI2CreateBuffer: BO alloc failed\n");
		free(buf);
		return NULL;
	}

	armsoc_bo_set_drawable(bo, pDraw);
	DRIBUF(buf)->name = armsoc_bo_name(bo);
	DRIBUF(buf)->pitch = armsoc_bo_pitch(bo);
	buf->bo = bo;

	if (canflip(pDraw) && attachment != DRI2BufferFrontLeft) {
		/* Create an fb around this buffer. This will fail and we will
		 * fall back to blitting if the display controller hardware
		 * cannot scan out this buffer (for example, if it doesn't
		 * support the format or there was insufficient scanout memory
		 * at buffer creation time). */
		int ret = armsoc_bo_add_fb(bo);
		if (ret) {
			WARNING_MSG(
					"Falling back to blitting a flippable window");
		}
	}

	/* Register Pixmap as having a buffer that can be accessed externally,
	 * so needs synchronised access */
	// FIXME ARMSOCRegisterExternalAccess(pPixmap);

	return DRIBUF(buf);
}