/* Get GEM handle for the pixmap */
Bool radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle)
{
    struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap);
#ifdef USE_GLAMOR
    ScreenPtr screen = pixmap->drawable.pScreen;
    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
#endif

    if (bo) {
	*handle = bo->handle;
	return TRUE;
    }

#ifdef USE_GLAMOR
    if (info->use_glamor) {
	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
	CARD16 stride;
	CARD32 size;
	int fd, r;

	if (!priv) {
	    priv = calloc(1, sizeof(*priv));
	    radeon_set_pixmap_private(pixmap, priv);
	}

	if (priv->handle_valid) {
	    *handle = priv->handle;
	    return TRUE;
	}

	fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size);
	if (fd < 0)
	    return FALSE;

	r = drmPrimeFDToHandle(info->dri2.drm_fd, fd, &priv->handle);
	close(fd);
	if (r == 0) {
	    struct drm_radeon_gem_set_tiling args = { .handle = priv->handle };

	    priv->handle_valid = TRUE;
	    *handle = priv->handle;

	    if (drmCommandWriteRead(info->dri2.drm_fd,
				    DRM_RADEON_GEM_GET_TILING, &args,
				    sizeof(args)) == 0)
		priv->tiling_flags = args.tiling_flags;

	    return TRUE;
	}
    }
#endif

    return FALSE;
}

uint32_t radeon_get_pixmap_tiling_flags(PixmapPtr pPix)
{
#ifdef USE_GLAMOR
    RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen));

    if (info->use_glamor) {
	struct radeon_pixmap *priv = radeon_get_pixmap_private(pPix);

	if (!priv || (!priv->bo && !priv->handle_valid)) {
	    uint32_t handle;

	    radeon_get_pixmap_handle(pPix, &handle);
	    priv = radeon_get_pixmap_private(pPix);
	}

	return priv ? priv->tiling_flags : 0;
    } else
#endif
    {
	struct radeon_exa_pixmap_priv *driver_priv;
	driver_priv = exaGetPixmapDriverPrivate(pPix);
	return driver_priv ? driver_priv->tiling_flags : 0;
    }
}
static PixmapPtr
radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
			unsigned usage)
{
	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
	RADEONInfoPtr info = RADEONPTR(scrn);
	struct radeon_pixmap *priv;
	PixmapPtr pixmap, new_pixmap = NULL;

	if (!RADEON_CREATE_PIXMAP_SHARED(usage)) {
		if (info->shadow_primary) {
			if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
				return fbCreatePixmap(screen, w, h, depth, usage);
		} else {
			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
			if (pixmap)
			    return pixmap;
		}
	}

	if (w > 32767 || h > 32767)
		return NullPixmap;

	if (depth == 1)
		return fbCreatePixmap(screen, w, h, depth, usage);

	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
		return fbCreatePixmap(screen, w, h, depth, usage);

	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
	if (pixmap == NullPixmap)
		return pixmap;

	if (w && h) {
		int stride;

		priv = calloc(1, sizeof (struct radeon_pixmap));
		if (priv == NULL)
			goto fallback_pixmap;

		priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage,
						  pixmap->drawable.bitsPerPixel,
						  &stride,
						  &priv->surface,
						  &priv->tiling_flags);
		if (!priv->bo)
			goto fallback_priv;

		radeon_set_pixmap_private(pixmap, priv);

		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);

		if (!radeon_glamor_create_textured_pixmap(pixmap, priv))
			goto fallback_glamor;

		pixmap->devPrivate.ptr = NULL;
	}

	return pixmap;

fallback_glamor:
	if (RADEON_CREATE_PIXMAP_SHARED(usage)) {
	/* XXX need further work to handle the DRI2 failure case.
	 * Glamor don't know how to handle a BO only pixmap. Put
	 * a warning indicator here.
	 */
		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
			   "Failed to create textured DRI2/PRIME pixmap.");
		return pixmap;
	}
	/* Create textured pixmap failed means glamor failed to
	 * create a texture from current BO for some reasons. We turn
	 * to create a new glamor pixmap and clean up current one.
	 * One thing need to be noted, this new pixmap doesn't
	 * has a priv and bo attached to it. It's glamor's responsbility
	 * to take care of it. Glamor will mark this new pixmap as a
	 * texture only pixmap and will never fallback to DDX layer
	 * afterwards.
	 */
	new_pixmap = glamor_create_pixmap(screen, w, h,	depth, usage);
	radeon_bo_unref(priv->bo);
fallback_priv:
	free(priv);
fallback_pixmap:
	fbDestroyPixmap(pixmap);
	if (new_pixmap)
		return new_pixmap;
	else
		return fbCreatePixmap(screen, w, h, depth, usage);
}