static inline Bool
exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b)
{
	msm_pixmap_exchange(draw2pix(dri2draw(pDraw, a)),
			draw2pix(dri2draw(pDraw, b)));
	exchange(a->name, b->name);
	return TRUE;
}
static inline Bool
exchangebufs(DrawablePtr pDraw, DRI2BufferPtr a, DRI2BufferPtr b)
{
	PixmapPtr aPix = draw2pix(dri2draw(pDraw, a));
	PixmapPtr bPix = draw2pix(dri2draw(pDraw, b));

	ARMSOCPixmapExchange(aPix, bPix);
	exchange(a->name, b->name);
	return TRUE;
}
/**
 * Create Buffer.
 */
static DRI2BufferPtr
MSMDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
		unsigned int format)
{
	ScreenPtr pScreen = pDraw->pScreen;
	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
	MSMDRI2BufferPtr buf = calloc(1, sizeof(*buf));
	PixmapPtr pPixmap;
	int ret;

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

	if (!buf) {
		return NULL;
	}

	if (attachment == DRI2BufferFrontLeft) {
		pPixmap = draw2pix(pDraw);
		pPixmap->refcnt++;
	} else {
		pPixmap = createpix(pDraw);
	}

	DRIBUF(buf)->attachment = attachment;
	DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8;
	DRIBUF(buf)->format = format;
	buf->refcnt = 1;
	buf->pPixmap = pPixmap;

	ret = msm_get_pixmap_name(pPixmap, &DRIBUF(buf)->name,
			&DRIBUF(buf)->pitch);
	if (ret) {
		ERROR_MSG("could not get buffer name: %d", ret);
		MSMDRI2DestroyBuffer(pDraw, DRIBUF(buf));
		return NULL;
	}

	return DRIBUF(buf);
}
/**
 * Helper function to implement video blit, handling clipping, damage, etc..
 *
 * TODO: move to EXA?
 */
int
OMAPVidCopyArea(DrawablePtr pSrcDraw, BoxPtr pSrcBox,
		DrawablePtr pOsdDraw, BoxPtr pOsdBox,
		DrawablePtr pDstDraw, BoxPtr pDstBox,
		OMAPPutTextureImageProc PutTextureImage, void *closure,
		RegionPtr clipBoxes)
{
	ScreenPtr pScreen = pDstDraw->pScreen;
	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
	PixmapPtr pSrcPix = draw2pix(pSrcDraw);
	PixmapPtr pOsdPix = draw2pix(pOsdDraw);
	PixmapPtr pDstPix = draw2pix(pDstDraw);
	pixman_fixed_t sx, sy, tx, ty;
	pixman_transform_t srcxfrm;
	BoxPtr pbox;
	int nbox, dx, dy, ret = Success;

#ifdef COMPOSITE
	DEBUG_MSG("--> %dx%d, %dx%d", pDstPix->screen_x, pDstPix->screen_y,
			pDstDraw->x, pDstDraw->y);
	/* Convert screen coords to pixmap coords */
	if (pDstPix->screen_x || pDstPix->screen_y) {
		RegionTranslate(clipBoxes, -pDstPix->screen_x, -pDstPix->screen_y);
	}
	dx = pDstPix->screen_x;
	dy = pDstPix->screen_y;
#else
	dx = 0;
	dy = 0;
#endif

	/* the clip-region gives coordinates in dst's coord space..  generate
	 * a transform that can be used to work backwards from dst->src coord
	 * space:
	 */
	sx = ((pixman_fixed_48_16_t) (pSrcBox->x2 - pSrcBox->x1) << 16) /
			(pDstBox->x2 - pDstBox->x1);
	sy = ((pixman_fixed_48_16_t) (pSrcBox->y2 - pSrcBox->y1) << 16) /
			(pDstBox->y2 - pDstBox->y1);
	tx = ((pixman_fixed_48_16_t)(pDstBox->x1 - pSrcBox->x1 - dx) << 16);
	ty = ((pixman_fixed_48_16_t)(pDstBox->y1 - pSrcBox->y1 - dy) << 16);

	pixman_transform_init_scale(&srcxfrm, sx, sy);
	pixman_transform_translate(NULL, &srcxfrm, tx, ty);

	// TODO generate transform for osd as well

	pbox = RegionRects(clipBoxes);
	nbox = RegionNumRects(clipBoxes);

	while (nbox--) {
		RegionRec damage;
		BoxRec dstb = *pbox;
		BoxRec srcb = *pbox;
		BoxRec osdb = *pbox;

		pixman_transform_bounds(&srcxfrm, &srcb);
		//pixman_transform_bounds(&osdxfrm, &osdb);

		DEBUG_MSG("%d,%d %d,%d -> %d,%d %d,%d",
				srcb.x1, srcb.y1, srcb.x2, srcb.y2,
				dstb.x1, dstb.y1, dstb.x2, dstb.y2);

		ret = PutTextureImage(pSrcPix, &srcb, pOsdPix, &osdb,
				pDstPix, &dstb, closure);
		if (ret != Success) {
			break;
		}

		RegionInit(&damage, &dstb, 1);

#ifdef COMPOSITE
		/* Convert screen coords to pixmap coords */
		if (pDstPix->screen_x || pDstPix->screen_y) {
			RegionTranslate(&damage, pDstPix->screen_x, pDstPix->screen_y);
		}
#endif

		DamageRegionAppend(pDstDraw, &damage);
		RegionUninit(&damage);

		pbox++;
	}

	DamageRegionProcessPending(pDstDraw);

	return ret;
}
static Bool create_buffer(DrawablePtr pDraw, struct ARMSOCDRI2BufferRec *buf)
{
	ScreenPtr pScreen = pDraw->pScreen;
	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
	struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
	DRI2BufferPtr buffer = DRIBUF(buf);
	PixmapPtr pPixmap = NULL;
	struct armsoc_bo *bo;
	int ret;

	if (buffer->attachment == DRI2BufferFrontLeft) {
		pPixmap = draw2pix(pDraw);
		pPixmap->refcnt++;
	} else {
		pPixmap = createpix(pDraw);
	}

	if (!pPixmap) {
		assert(buffer->attachment != DRI2BufferFrontLeft);
		ERROR_MSG("Failed to create back buffer for window");
		goto fail;
	}

	if (buffer->attachment == DRI2BufferBackLeft && pARMSOC->driNumBufs > 2) {
		buf->pPixmaps = calloc(pARMSOC->driNumBufs-1,
				sizeof(PixmapPtr));
		buf->numPixmaps = pARMSOC->driNumBufs-1;
	} else {
		buf->pPixmaps = malloc(sizeof(PixmapPtr));
		buf->numPixmaps = 1;
	}

	if (!buf->pPixmaps) {
		ERROR_MSG("Failed to allocate PixmapPtr array for DRI2Buffer");
		goto fail;
	}

	buf->pPixmaps[0] = pPixmap;
	assert(buf->currentPixmap == 0);

	bo = ARMSOCPixmapBo(pPixmap);
	if (!bo) {
		ERROR_MSG(
				"Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
		goto fail;
	}

	DRIBUF(buf)->pitch = exaGetPixmapPitch(pPixmap);
	DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8;
	DRIBUF(buf)->flags = 0;
	buf->refcnt = 1;
	buf->previous_canflip = canflip(pDraw);

	ret = armsoc_bo_get_name(bo, &DRIBUF(buf)->name);
	if (ret) {
		ERROR_MSG("could not get buffer name: %d", ret);
		goto fail;
	}

	if (canflip(pDraw) && buffer->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");
		}
#if DRI2INFOREC_VERSION >= 6
		else if (FALSE == DRI2SwapLimit(pDraw, pARMSOC->swap_chain_size)) {
			WARNING_MSG(
				"Failed to set DRI2SwapLimit(%x,%d)",
				(unsigned int)pDraw, pARMSOC->swap_chain_size);
		}
#endif /* DRI2INFOREC_VERSION >= 6 */
	}

	DRI2_BUFFER_SET_FB(DRIBUF(buf)->flags, armsoc_bo_get_fb(bo) > 0 ? 1 : 0);
	DRI2_BUFFER_SET_REUSED(DRIBUF(buf)->flags, 0);
	/* Register Pixmap as having a buffer that can be accessed externally,
	 * so needs synchronised access */
	ARMSOCRegisterExternalAccess(pPixmap);

	return TRUE;

fail:
	if (pPixmap != NULL) {
		if (buffer->attachment != DRI2BufferFrontLeft)
			pScreen->DestroyPixmap(pPixmap);
		else
			pPixmap->refcnt--;
	}

	return FALSE;
}