sna_dri2.c revision 42542f5f
142542f5fSchristos/**************************************************************************
242542f5fSchristos
342542f5fSchristosCopyright 2001 VA Linux Systems Inc., Fremont, California.
442542f5fSchristosCopyright © 2002 by David Dawes
542542f5fSchristos
642542f5fSchristosAll Rights Reserved.
742542f5fSchristos
842542f5fSchristosPermission is hereby granted, free of charge, to any person obtaining a
942542f5fSchristoscopy of this software and associated documentation files (the "Software"),
1042542f5fSchristosto deal in the Software without restriction, including without limitation
1142542f5fSchristoson the rights to use, copy, modify, merge, publish, distribute, sub
1242542f5fSchristoslicense, and/or sell copies of the Software, and to permit persons to whom
1342542f5fSchristosthe Software is furnished to do so, subject to the following conditions:
1442542f5fSchristos
1542542f5fSchristosThe above copyright notice and this permission notice (including the next
1642542f5fSchristosparagraph) shall be included in all copies or substantial portions of the
1742542f5fSchristosSoftware.
1842542f5fSchristos
1942542f5fSchristosTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2042542f5fSchristosIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2142542f5fSchristosFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2242542f5fSchristosATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
2342542f5fSchristosDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2442542f5fSchristosOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2542542f5fSchristosUSE OR OTHER DEALINGS IN THE SOFTWARE.
2642542f5fSchristos
2742542f5fSchristos**************************************************************************/
2842542f5fSchristos
2942542f5fSchristos/*
3042542f5fSchristos * Authors: Jeff Hartmann <jhartmann@valinux.com>
3142542f5fSchristos *          David Dawes <dawes@xfree86.org>
3242542f5fSchristos *          Keith Whitwell <keith@tungstengraphics.com>
3342542f5fSchristos */
3442542f5fSchristos
3542542f5fSchristos#ifdef HAVE_CONFIG_H
3642542f5fSchristos#include "config.h"
3742542f5fSchristos#endif
3842542f5fSchristos
3942542f5fSchristos#include <errno.h>
4042542f5fSchristos#include <time.h>
4142542f5fSchristos#include <string.h>
4242542f5fSchristos#include <unistd.h>
4342542f5fSchristos#include <poll.h>
4442542f5fSchristos
4542542f5fSchristos#include "sna.h"
4642542f5fSchristos#include "intel_options.h"
4742542f5fSchristos
4842542f5fSchristos#include <xf86drm.h>
4942542f5fSchristos#include <i915_drm.h>
5042542f5fSchristos#include <dri2.h>
5142542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) && defined(COMPOSITE)
5242542f5fSchristos#include <compositeext.h>
5342542f5fSchristos#define CHECK_FOR_COMPOSITOR
5442542f5fSchristos#endif
5542542f5fSchristos
5642542f5fSchristos#define DBG_CAN_FLIP 1
5742542f5fSchristos#define DBG_CAN_XCHG 1
5842542f5fSchristos
5942542f5fSchristos#define DBG_FORCE_COPY -1 /* KGEM_BLT or KGEM_3D */
6042542f5fSchristos
6142542f5fSchristos#if DRI2INFOREC_VERSION < 2
6242542f5fSchristos#error DRI2 version supported by the Xserver is too old
6342542f5fSchristos#endif
6442542f5fSchristos
6542542f5fSchristosstatic inline struct kgem_bo *ref(struct kgem_bo *bo)
6642542f5fSchristos{
6742542f5fSchristos	assert(bo->refcnt);
6842542f5fSchristos	bo->refcnt++;
6942542f5fSchristos	return bo;
7042542f5fSchristos}
7142542f5fSchristos
7242542f5fSchristosstatic inline void unref(struct kgem_bo *bo)
7342542f5fSchristos{
7442542f5fSchristos	assert(bo->refcnt > 1);
7542542f5fSchristos	bo->refcnt--;
7642542f5fSchristos}
7742542f5fSchristos
7842542f5fSchristosstruct sna_dri2_private {
7942542f5fSchristos	PixmapPtr pixmap;
8042542f5fSchristos	struct kgem_bo *bo;
8142542f5fSchristos	DRI2Buffer2Ptr proxy;
8242542f5fSchristos	bool stale;
8342542f5fSchristos	uint32_t size;
8442542f5fSchristos	int refcnt;
8542542f5fSchristos};
8642542f5fSchristos
8742542f5fSchristosstatic inline struct sna_dri2_private *
8842542f5fSchristosget_private(void *buffer)
8942542f5fSchristos{
9042542f5fSchristos	return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
9142542f5fSchristos}
9242542f5fSchristos
9342542f5fSchristos#if DRI2INFOREC_VERSION >= 4
9442542f5fSchristosenum event_type {
9542542f5fSchristos	WAITMSC = 0,
9642542f5fSchristos	SWAP,
9742542f5fSchristos	SWAP_WAIT,
9842542f5fSchristos	SWAP_THROTTLE,
9942542f5fSchristos	FLIP,
10042542f5fSchristos	FLIP_THROTTLE,
10142542f5fSchristos	FLIP_COMPLETE,
10242542f5fSchristos	FLIP_ASYNC,
10342542f5fSchristos};
10442542f5fSchristos
10542542f5fSchristosstruct dri_bo {
10642542f5fSchristos	struct list link;
10742542f5fSchristos	struct kgem_bo *bo;
10842542f5fSchristos	uint32_t name;
10942542f5fSchristos};
11042542f5fSchristos
11142542f5fSchristosstruct sna_dri2_event {
11242542f5fSchristos	DrawablePtr draw;
11342542f5fSchristos	ClientPtr client;
11442542f5fSchristos	enum event_type type;
11542542f5fSchristos	xf86CrtcPtr crtc;
11642542f5fSchristos	int pipe;
11742542f5fSchristos	bool queued;
11842542f5fSchristos
11942542f5fSchristos	/* for swaps & flips only */
12042542f5fSchristos	DRI2SwapEventPtr event_complete;
12142542f5fSchristos	void *event_data;
12242542f5fSchristos	DRI2BufferPtr front;
12342542f5fSchristos	DRI2BufferPtr back;
12442542f5fSchristos	struct kgem_bo *bo;
12542542f5fSchristos
12642542f5fSchristos	struct sna_dri2_event *chain;
12742542f5fSchristos
12842542f5fSchristos	struct list cache;
12942542f5fSchristos	struct list link;
13042542f5fSchristos
13142542f5fSchristos	int mode;
13242542f5fSchristos};
13342542f5fSchristos
13442542f5fSchristosstatic void sna_dri2_flip_event(struct sna *sna,
13542542f5fSchristos				struct sna_dri2_event *flip);
13642542f5fSchristos
13742542f5fSchristosstatic void
13842542f5fSchristossna_dri2_get_back(struct sna *sna,
13942542f5fSchristos		  DrawablePtr draw,
14042542f5fSchristos		  DRI2BufferPtr back,
14142542f5fSchristos		  struct sna_dri2_event *info)
14242542f5fSchristos{
14342542f5fSchristos	struct kgem_bo *bo;
14442542f5fSchristos	uint32_t name;
14542542f5fSchristos	bool reuse;
14642542f5fSchristos
14742542f5fSchristos	DBG(("%s: draw size=%dx%d, buffer size=%dx%d\n",
14842542f5fSchristos	     __FUNCTION__, draw->width, draw->height,
14942542f5fSchristos	     get_private(back)->size & 0xffff, get_private(back)->size >> 16));
15042542f5fSchristos	reuse = (draw->height << 16 | draw->width) == get_private(back)->size;
15142542f5fSchristos	if (reuse) {
15242542f5fSchristos		bo = get_private(back)->bo;
15342542f5fSchristos		assert(bo->refcnt);
15442542f5fSchristos		DBG(("%s: back buffer handle=%d, scanout?=%d, refcnt=%d\n",
15542542f5fSchristos					__FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
15642542f5fSchristos		if (bo->active_scanout == 0) {
15742542f5fSchristos			DBG(("%s: reuse unattached back\n", __FUNCTION__));
15842542f5fSchristos			get_private(back)->stale = false;
15942542f5fSchristos			return;
16042542f5fSchristos		}
16142542f5fSchristos	}
16242542f5fSchristos
16342542f5fSchristos	bo = NULL;
16442542f5fSchristos	if (info) {
16542542f5fSchristos		struct dri_bo *c;
16642542f5fSchristos		list_for_each_entry(c, &info->cache, link) {
16742542f5fSchristos			if (c->bo && c->bo->scanout == 0) {
16842542f5fSchristos				bo = c->bo;
16942542f5fSchristos				name = c->name;
17042542f5fSchristos				DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle));
17142542f5fSchristos				list_move_tail(&c->link, &info->cache);
17242542f5fSchristos				c->bo = NULL;
17342542f5fSchristos			}
17442542f5fSchristos		}
17542542f5fSchristos	}
17642542f5fSchristos	if (bo == NULL) {
17742542f5fSchristos		DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
17842542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
17942542f5fSchristos				    draw->width, draw->height, draw->bitsPerPixel,
18042542f5fSchristos				    get_private(back)->bo->tiling,
18142542f5fSchristos				    get_private(back)->bo->scanout ? CREATE_SCANOUT : 0);
18242542f5fSchristos		if (bo == NULL)
18342542f5fSchristos			return;
18442542f5fSchristos
18542542f5fSchristos		name = kgem_bo_flink(&sna->kgem, bo);
18642542f5fSchristos		if (name == 0) {
18742542f5fSchristos			kgem_bo_destroy(&sna->kgem, bo);
18842542f5fSchristos			return;
18942542f5fSchristos		}
19042542f5fSchristos	}
19142542f5fSchristos	assert(bo->active_scanout == 0);
19242542f5fSchristos
19342542f5fSchristos	if (info && reuse) {
19442542f5fSchristos		bool found = false;
19542542f5fSchristos		struct dri_bo *c;
19642542f5fSchristos
19742542f5fSchristos		list_for_each_entry_reverse(c, &info->cache, link) {
19842542f5fSchristos			if (c->bo == NULL) {
19942542f5fSchristos				found = true;
20042542f5fSchristos				_list_del(&c->link);
20142542f5fSchristos				break;
20242542f5fSchristos			}
20342542f5fSchristos		}
20442542f5fSchristos		if (!found)
20542542f5fSchristos			c = malloc(sizeof(*c));
20642542f5fSchristos		if (c != NULL) {
20742542f5fSchristos			c->bo = ref(get_private(back)->bo);
20842542f5fSchristos			c->name = back->name;
20942542f5fSchristos			list_add(&c->link, &info->cache);
21042542f5fSchristos			DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name));
21142542f5fSchristos		}
21242542f5fSchristos	}
21342542f5fSchristos
21442542f5fSchristos	assert(bo != get_private(back)->bo);
21542542f5fSchristos	kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
21642542f5fSchristos
21742542f5fSchristos	get_private(back)->bo = bo;
21842542f5fSchristos	get_private(back)->size = draw->height << 16 | draw->width;
21942542f5fSchristos	back->pitch = bo->pitch;
22042542f5fSchristos	back->name = name;
22142542f5fSchristos
22242542f5fSchristos	get_private(back)->stale = false;
22342542f5fSchristos}
22442542f5fSchristos
22542542f5fSchristosstruct dri2_window {
22642542f5fSchristos	DRI2BufferPtr front;
22742542f5fSchristos	struct sna_dri2_event *chain;
22842542f5fSchristos	xf86CrtcPtr crtc;
22942542f5fSchristos	int64_t msc_delta;
23042542f5fSchristos};
23142542f5fSchristos
23242542f5fSchristosstatic struct dri2_window *dri2_window(WindowPtr win)
23342542f5fSchristos{
23442542f5fSchristos	assert(win->drawable.type != DRAWABLE_PIXMAP);
23542542f5fSchristos	return ((void **)__get_private(win, sna_window_key))[1];
23642542f5fSchristos}
23742542f5fSchristos
23842542f5fSchristosstatic struct sna_dri2_event *
23942542f5fSchristosdri2_chain(DrawablePtr d)
24042542f5fSchristos{
24142542f5fSchristos	struct dri2_window *priv = dri2_window((WindowPtr)d);
24242542f5fSchristos	assert(priv != NULL);
24342542f5fSchristos	return priv->chain;
24442542f5fSchristos}
24542542f5fSchristosinline static DRI2BufferPtr dri2_window_get_front(WindowPtr win) { return dri2_window(win)->front; }
24642542f5fSchristos#else
24742542f5fSchristosinline static void *dri2_window_get_front(WindowPtr win) { return NULL; }
24842542f5fSchristos#endif
24942542f5fSchristos
25042542f5fSchristos#if DRI2INFOREC_VERSION < 6
25142542f5fSchristos
25242542f5fSchristos#define xorg_can_triple_buffer(ptr) 0
25342542f5fSchristos#define swap_limit(d, l) false
25442542f5fSchristos
25542542f5fSchristos#else
25642542f5fSchristos
25742542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,904,0)
25842542f5fSchristos/* Prime fixed for triple buffer support */
25942542f5fSchristos#define xorg_can_triple_buffer(ptr) 1
26042542f5fSchristos#elif XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,12,99,901,0)
26142542f5fSchristos/* Before numGPUScreens was introduced */
26242542f5fSchristos#define xorg_can_triple_buffer(ptr) 1
26342542f5fSchristos#else
26442542f5fSchristos/* Subject to crashers when combining triple buffering and Prime */
26542542f5fSchristosinline static bool xorg_can_triple_buffer(struct sna *sna)
26642542f5fSchristos{
26742542f5fSchristos	return screenInfo.numGPUScreens == 0;
26842542f5fSchristos}
26942542f5fSchristos#endif
27042542f5fSchristos
27142542f5fSchristosstatic Bool
27242542f5fSchristossna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
27342542f5fSchristos{
27442542f5fSchristos	DBG(("%s: swap limit set to %d\n", __FUNCTION__, swap_limit));
27542542f5fSchristos	return swap_limit >= 1;
27642542f5fSchristos}
27742542f5fSchristos
27842542f5fSchristosstatic void
27942542f5fSchristossna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
28042542f5fSchristos{
28142542f5fSchristos	DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n",
28242542f5fSchristos	     __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
28342542f5fSchristos	     buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
28442542f5fSchristos	assert(get_private(buffer)->refcnt);
28542542f5fSchristos	assert(get_private(buffer)->bo->refcnt > get_private(buffer)->bo->active_scanout);
28642542f5fSchristos
28742542f5fSchristos	if (buffer->attachment == DRI2BufferBackLeft &&
28842542f5fSchristos	    draw->type != DRAWABLE_PIXMAP) {
28942542f5fSchristos		DBG(("%s: replacing back buffer\n", __FUNCTION__));
29042542f5fSchristos		sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
29142542f5fSchristos
29242542f5fSchristos		assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
29342542f5fSchristos		assert(get_private(buffer)->bo->refcnt);
29442542f5fSchristos		assert(get_private(buffer)->bo->active_scanout == 0);
29542542f5fSchristos	}
29642542f5fSchristos}
29742542f5fSchristos
29842542f5fSchristosstatic bool swap_limit(DrawablePtr draw, int limit)
29942542f5fSchristos{
30042542f5fSchristos	DBG(("%s: draw=%ld setting swap limit to %d\n", __FUNCTION__, (long)draw->id, limit));
30142542f5fSchristos	DRI2SwapLimit(draw, limit);
30242542f5fSchristos	return true;
30342542f5fSchristos}
30442542f5fSchristos#endif
30542542f5fSchristos
30642542f5fSchristos#if DRI2INFOREC_VERSION < 10
30742542f5fSchristos#undef USE_ASYNC_SWAP
30842542f5fSchristos#define USE_ASYNC_SWAP 0
30942542f5fSchristos#endif
31042542f5fSchristos
31142542f5fSchristos#define COLOR_PREFER_TILING_Y 0
31242542f5fSchristos
31342542f5fSchristos/* Prefer to enable TILING_Y if this buffer will never be a
31442542f5fSchristos * candidate for pageflipping
31542542f5fSchristos */
31642542f5fSchristosstatic uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
31742542f5fSchristos{
31842542f5fSchristos	uint32_t tiling;
31942542f5fSchristos
32042542f5fSchristos	if (COLOR_PREFER_TILING_Y &&
32142542f5fSchristos	    (draw->width  != sna->front->drawable.width ||
32242542f5fSchristos	     draw->height != sna->front->drawable.height))
32342542f5fSchristos		tiling = I915_TILING_Y;
32442542f5fSchristos	else
32542542f5fSchristos		tiling = I915_TILING_X;
32642542f5fSchristos
32742542f5fSchristos	return kgem_choose_tiling(&sna->kgem, -tiling,
32842542f5fSchristos				  draw->width,
32942542f5fSchristos				  draw->height,
33042542f5fSchristos				  draw->bitsPerPixel);
33142542f5fSchristos}
33242542f5fSchristos
33342542f5fSchristosstatic uint32_t other_tiling(struct sna *sna, DrawablePtr draw)
33442542f5fSchristos{
33542542f5fSchristos	/* XXX Can mix color X / depth Y? */
33642542f5fSchristos	return kgem_choose_tiling(&sna->kgem,
33742542f5fSchristos				  sna->kgem.gen >= 040 ? -I915_TILING_Y : -I915_TILING_X,
33842542f5fSchristos				  draw->width,
33942542f5fSchristos				  draw->height,
34042542f5fSchristos				  draw->bitsPerPixel);
34142542f5fSchristos}
34242542f5fSchristos
34342542f5fSchristosstatic struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
34442542f5fSchristos					  PixmapPtr pixmap)
34542542f5fSchristos{
34642542f5fSchristos	struct sna_pixmap *priv;
34742542f5fSchristos	int tiling;
34842542f5fSchristos
34942542f5fSchristos	DBG(("%s: attaching DRI client to pixmap=%ld\n",
35042542f5fSchristos	     __FUNCTION__, pixmap->drawable.serialNumber));
35142542f5fSchristos
35242542f5fSchristos	priv = sna_pixmap(pixmap);
35342542f5fSchristos	if (priv != NULL && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
35442542f5fSchristos		DBG(("%s: SHM or unattached Pixmap, BadAlloc\n", __FUNCTION__));
35542542f5fSchristos		return NULL;
35642542f5fSchristos	}
35742542f5fSchristos
35842542f5fSchristos	priv = sna_pixmap_move_to_gpu(pixmap,
35942542f5fSchristos				      MOVE_READ | __MOVE_FORCE | __MOVE_DRI);
36042542f5fSchristos	if (priv == NULL) {
36142542f5fSchristos		DBG(("%s: failed to move to GPU, BadAlloc\n", __FUNCTION__));
36242542f5fSchristos		return NULL;
36342542f5fSchristos	}
36442542f5fSchristos
36542542f5fSchristos	assert(priv->flush == false);
36642542f5fSchristos	assert(priv->cpu_damage == NULL);
36742542f5fSchristos	assert(priv->gpu_bo);
36842542f5fSchristos	assert(priv->gpu_bo->proxy == NULL);
36942542f5fSchristos	assert(priv->gpu_bo->flush == false);
37042542f5fSchristos
37142542f5fSchristos	tiling = color_tiling(sna, &pixmap->drawable);
37242542f5fSchristos	if (tiling < 0)
37342542f5fSchristos		tiling = -tiling;
37442542f5fSchristos	if (priv->gpu_bo->tiling != tiling)
37542542f5fSchristos		sna_pixmap_change_tiling(pixmap, tiling);
37642542f5fSchristos
37742542f5fSchristos	return priv->gpu_bo;
37842542f5fSchristos}
37942542f5fSchristos
38042542f5fSchristospure static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
38142542f5fSchristos{
38242542f5fSchristos	assert(pixmap->refcnt);
38342542f5fSchristos	return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
38442542f5fSchristos}
38542542f5fSchristos
38642542f5fSchristosstatic inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
38742542f5fSchristos{
38842542f5fSchristos	assert(pixmap->refcnt);
38942542f5fSchristos	((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
39042542f5fSchristos}
39142542f5fSchristos
39242542f5fSchristosvoid
39342542f5fSchristossna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
39442542f5fSchristos{
39542542f5fSchristos	DRI2BufferPtr buffer;
39642542f5fSchristos	struct sna_dri2_private *private;
39742542f5fSchristos
39842542f5fSchristos	buffer = sna_pixmap_get_buffer(pixmap);
39942542f5fSchristos	if (buffer == NULL)
40042542f5fSchristos		return;
40142542f5fSchristos
40242542f5fSchristos	DBG(("%s: pixmap=%ld, old handle=%d, new handle=%d\n", __FUNCTION__,
40342542f5fSchristos	     pixmap->drawable.serialNumber,
40442542f5fSchristos	     get_private(buffer)->bo->handle,
40542542f5fSchristos	     sna_pixmap(pixmap)->gpu_bo->handle));
40642542f5fSchristos
40742542f5fSchristos	private = get_private(buffer);
40842542f5fSchristos	assert(private->pixmap == pixmap);
40942542f5fSchristos
41042542f5fSchristos	assert(bo != private->bo);
41142542f5fSchristos	if (private->bo == bo)
41242542f5fSchristos		return;
41342542f5fSchristos
41442542f5fSchristos	DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
41542542f5fSchristos	private->bo->flush = false;
41642542f5fSchristos	kgem_bo_destroy(&sna->kgem, private->bo);
41742542f5fSchristos
41842542f5fSchristos	buffer->name = kgem_bo_flink(&sna->kgem, bo);
41942542f5fSchristos	private->bo = ref(bo);
42042542f5fSchristos
42142542f5fSchristos	DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
42242542f5fSchristos	bo->flush = true;
42342542f5fSchristos	assert(sna_pixmap(pixmap)->flush);
42442542f5fSchristos
42542542f5fSchristos	/* XXX DRI2InvalidateDrawable(&pixmap->drawable); */
42642542f5fSchristos}
42742542f5fSchristos
42842542f5fSchristosstatic DRI2Buffer2Ptr
42942542f5fSchristossna_dri2_create_buffer(DrawablePtr draw,
43042542f5fSchristos		       unsigned int attachment,
43142542f5fSchristos		       unsigned int format)
43242542f5fSchristos{
43342542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
43442542f5fSchristos	DRI2Buffer2Ptr buffer;
43542542f5fSchristos	struct sna_dri2_private *private;
43642542f5fSchristos	PixmapPtr pixmap;
43742542f5fSchristos	struct kgem_bo *bo;
43842542f5fSchristos	unsigned flags = 0;
43942542f5fSchristos	uint32_t size;
44042542f5fSchristos	int bpp;
44142542f5fSchristos
44242542f5fSchristos	DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d)\n",
44342542f5fSchristos	     __FUNCTION__,
44442542f5fSchristos	     get_drawable_pixmap(draw)->drawable.serialNumber,
44542542f5fSchristos	     attachment, format, draw->width, draw->height));
44642542f5fSchristos
44742542f5fSchristos	pixmap = NULL;
44842542f5fSchristos	size = (uint32_t)draw->height << 16 | draw->width;
44942542f5fSchristos	switch (attachment) {
45042542f5fSchristos	case DRI2BufferFrontLeft:
45142542f5fSchristos		pixmap = get_drawable_pixmap(draw);
45242542f5fSchristos		buffer = NULL;
45342542f5fSchristos		if (draw->type != DRAWABLE_PIXMAP)
45442542f5fSchristos			buffer = dri2_window_get_front((WindowPtr)draw);
45542542f5fSchristos		if (buffer == NULL)
45642542f5fSchristos			buffer = sna_pixmap_get_buffer(pixmap);
45742542f5fSchristos		if (buffer) {
45842542f5fSchristos			private = get_private(buffer);
45942542f5fSchristos
46042542f5fSchristos			DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld %dx%d, handle=%d, name=%d\n",
46142542f5fSchristos			     __FUNCTION__,
46242542f5fSchristos			     draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
46342542f5fSchristos			     draw->width, draw->height,
46442542f5fSchristos			     pixmap->drawable.serialNumber,
46542542f5fSchristos			     pixmap->drawable.width,
46642542f5fSchristos			     pixmap->drawable.height,
46742542f5fSchristos			     private->bo->handle, buffer->name));
46842542f5fSchristos
46942542f5fSchristos			assert(private->pixmap == pixmap);
47042542f5fSchristos			assert(sna_pixmap(pixmap)->flush);
47142542f5fSchristos			assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
47242542f5fSchristos			assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
47342542f5fSchristos
47442542f5fSchristos			private->refcnt++;
47542542f5fSchristos			return buffer;
47642542f5fSchristos		}
47742542f5fSchristos
47842542f5fSchristos		bo = sna_pixmap_set_dri(sna, pixmap);
47942542f5fSchristos		if (bo == NULL)
48042542f5fSchristos			return NULL;
48142542f5fSchristos
48242542f5fSchristos		assert(sna_pixmap(pixmap) != NULL);
48342542f5fSchristos
48442542f5fSchristos		bo = ref(bo);
48542542f5fSchristos		bpp = pixmap->drawable.bitsPerPixel;
48642542f5fSchristos		if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB))
48742542f5fSchristos			flags |= CREATE_SCANOUT;
48842542f5fSchristos		DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n",
48942542f5fSchristos		     __FUNCTION__,
49042542f5fSchristos		     pixmap->drawable.width, pixmap->drawable.height,
49142542f5fSchristos		     pixmap, pixmap->refcnt, flags & CREATE_SCANOUT));
49242542f5fSchristos		size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width;
49342542f5fSchristos		break;
49442542f5fSchristos
49542542f5fSchristos	case DRI2BufferBackLeft:
49642542f5fSchristos		if (draw->type != DRAWABLE_PIXMAP) {
49742542f5fSchristos			if (dri2_window_get_front((WindowPtr)draw))
49842542f5fSchristos				flags |= CREATE_SCANOUT;
49942542f5fSchristos			if (draw->width  == sna->front->drawable.width &&
50042542f5fSchristos			    draw->height == sna->front->drawable.height &&
50142542f5fSchristos			    (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
50242542f5fSchristos				flags |= CREATE_SCANOUT;
50342542f5fSchristos		}
50442542f5fSchristos	case DRI2BufferBackRight:
50542542f5fSchristos	case DRI2BufferFrontRight:
50642542f5fSchristos	case DRI2BufferFakeFrontLeft:
50742542f5fSchristos	case DRI2BufferFakeFrontRight:
50842542f5fSchristos		bpp = draw->bitsPerPixel;
50942542f5fSchristos		DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n",
51042542f5fSchristos		     __FUNCTION__,
51142542f5fSchristos		     draw->width, draw->height,
51242542f5fSchristos		     flags & CREATE_SCANOUT));
51342542f5fSchristos
51442542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
51542542f5fSchristos				    draw->width,
51642542f5fSchristos				    draw->height,
51742542f5fSchristos				    draw->bitsPerPixel,
51842542f5fSchristos				    color_tiling(sna, draw),
51942542f5fSchristos				    flags);
52042542f5fSchristos		break;
52142542f5fSchristos
52242542f5fSchristos	case DRI2BufferStencil:
52342542f5fSchristos		/*
52442542f5fSchristos		 * The stencil buffer has quirky pitch requirements.  From Vol
52542542f5fSchristos		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
52642542f5fSchristos		 * Pitch":
52742542f5fSchristos		 *    The pitch must be set to 2x the value computed based on
52842542f5fSchristos		 *    width, as the stencil buffer is stored with two rows
52942542f5fSchristos		 *    interleaved.
53042542f5fSchristos		 * To accomplish this, we resort to the nasty hack of doubling
53142542f5fSchristos		 * the drm region's cpp and halving its height.
53242542f5fSchristos		 *
53342542f5fSchristos		 * If we neglect to double the pitch, then
53442542f5fSchristos		 * drm_intel_gem_bo_map_gtt() maps the memory incorrectly.
53542542f5fSchristos		 *
53642542f5fSchristos		 * The alignment for W-tiling is quite different to the
53742542f5fSchristos		 * nominal no-tiling case, so we have to account for
53842542f5fSchristos		 * the tiled access pattern explicitly.
53942542f5fSchristos		 *
54042542f5fSchristos		 * The stencil buffer is W tiled. However, we request from
54142542f5fSchristos		 * the kernel a non-tiled buffer because the kernel does
54242542f5fSchristos		 * not understand W tiling and the GTT is incapable of
54342542f5fSchristos		 * W fencing.
54442542f5fSchristos		 */
54542542f5fSchristos		bpp = format ? format : draw->bitsPerPixel;
54642542f5fSchristos		bpp *= 2;
54742542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
54842542f5fSchristos				    ALIGN(draw->width, 64),
54942542f5fSchristos				    ALIGN((draw->height + 1) / 2, 64),
55042542f5fSchristos				    bpp, I915_TILING_NONE, flags);
55142542f5fSchristos		break;
55242542f5fSchristos
55342542f5fSchristos	case DRI2BufferDepth:
55442542f5fSchristos	case DRI2BufferDepthStencil:
55542542f5fSchristos	case DRI2BufferHiz:
55642542f5fSchristos	case DRI2BufferAccum:
55742542f5fSchristos		bpp = format ? format : draw->bitsPerPixel,
55842542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
55942542f5fSchristos				    draw->width, draw->height, bpp,
56042542f5fSchristos				    other_tiling(sna, draw),
56142542f5fSchristos				    flags);
56242542f5fSchristos		break;
56342542f5fSchristos
56442542f5fSchristos	default:
56542542f5fSchristos		return NULL;
56642542f5fSchristos	}
56742542f5fSchristos	if (bo == NULL)
56842542f5fSchristos		return NULL;
56942542f5fSchristos
57042542f5fSchristos	buffer = calloc(1, sizeof *buffer + sizeof *private);
57142542f5fSchristos	if (buffer == NULL)
57242542f5fSchristos		goto err;
57342542f5fSchristos
57442542f5fSchristos	private = get_private(buffer);
57542542f5fSchristos	buffer->attachment = attachment;
57642542f5fSchristos	buffer->pitch = bo->pitch;
57742542f5fSchristos	buffer->cpp = bpp / 8;
57842542f5fSchristos	buffer->driverPrivate = private;
57942542f5fSchristos	buffer->format = format;
58042542f5fSchristos	buffer->flags = 0;
58142542f5fSchristos	buffer->name = kgem_bo_flink(&sna->kgem, bo);
58242542f5fSchristos	private->refcnt = 1;
58342542f5fSchristos	private->bo = bo;
58442542f5fSchristos	private->pixmap = pixmap;
58542542f5fSchristos	private->size = size;
58642542f5fSchristos
58742542f5fSchristos	if (buffer->name == 0)
58842542f5fSchristos		goto err;
58942542f5fSchristos
59042542f5fSchristos	if (pixmap) {
59142542f5fSchristos		struct sna_pixmap *priv;
59242542f5fSchristos
59342542f5fSchristos		assert(attachment == DRI2BufferFrontLeft);
59442542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == NULL);
59542542f5fSchristos
59642542f5fSchristos		sna_pixmap_set_buffer(pixmap, buffer);
59742542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == buffer);
59842542f5fSchristos		pixmap->refcnt++;
59942542f5fSchristos
60042542f5fSchristos		priv = sna_pixmap(pixmap);
60142542f5fSchristos		assert(priv->flush == false);
60242542f5fSchristos		assert((priv->pinned & PIN_DRI2) == 0);
60342542f5fSchristos
60442542f5fSchristos		/* Don't allow this named buffer to be replaced */
60542542f5fSchristos		priv->pinned |= PIN_DRI2;
60642542f5fSchristos
60742542f5fSchristos		/* We need to submit any modifications to and reads from this
60842542f5fSchristos		 * buffer before we send any reply to the Client.
60942542f5fSchristos		 *
61042542f5fSchristos		 * As we don't track which Client, we flush for all.
61142542f5fSchristos		 */
61242542f5fSchristos		DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
61342542f5fSchristos		priv->gpu_bo->flush = true;
61442542f5fSchristos		if (priv->gpu_bo->exec)
61542542f5fSchristos			sna->kgem.flush = 1;
61642542f5fSchristos
61742542f5fSchristos		priv->flush |= 1;
61842542f5fSchristos		if (draw->type == DRAWABLE_PIXMAP) {
61942542f5fSchristos			/* DRI2 renders directly into GLXPixmaps, treat as hostile */
62042542f5fSchristos			kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
62142542f5fSchristos			sna_damage_all(&priv->gpu_damage, pixmap);
62242542f5fSchristos			priv->clear = false;
62342542f5fSchristos			priv->cpu = false;
62442542f5fSchristos			priv->flush |= 2;
62542542f5fSchristos		}
62642542f5fSchristos
62742542f5fSchristos		sna_accel_watch_flush(sna, 1);
62842542f5fSchristos	}
62942542f5fSchristos
63042542f5fSchristos	return buffer;
63142542f5fSchristos
63242542f5fSchristoserr:
63342542f5fSchristos	kgem_bo_destroy(&sna->kgem, bo);
63442542f5fSchristos	free(buffer);
63542542f5fSchristos	return NULL;
63642542f5fSchristos}
63742542f5fSchristos
63842542f5fSchristosstatic void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
63942542f5fSchristos{
64042542f5fSchristos	struct sna_dri2_private *private = get_private(buffer);
64142542f5fSchristos
64242542f5fSchristos	if (buffer == NULL)
64342542f5fSchristos		return;
64442542f5fSchristos
64542542f5fSchristos	DBG(("%s: %p [handle=%d] -- refcnt=%d, pixmap=%ld\n",
64642542f5fSchristos	     __FUNCTION__, buffer, private->bo->handle, private->refcnt,
64742542f5fSchristos	     private->pixmap ? private->pixmap->drawable.serialNumber : 0));
64842542f5fSchristos	assert(private->refcnt > 0);
64942542f5fSchristos	if (--private->refcnt)
65042542f5fSchristos		return;
65142542f5fSchristos
65242542f5fSchristos	assert(private->bo);
65342542f5fSchristos
65442542f5fSchristos	if (private->proxy) {
65542542f5fSchristos		DBG(("%s: destroying proxy\n", __FUNCTION__));
65642542f5fSchristos		_sna_dri2_destroy_buffer(sna, private->proxy);
65742542f5fSchristos		private->pixmap = NULL;
65842542f5fSchristos	}
65942542f5fSchristos
66042542f5fSchristos	if (private->pixmap) {
66142542f5fSchristos		PixmapPtr pixmap = private->pixmap;
66242542f5fSchristos		struct sna_pixmap *priv = sna_pixmap(pixmap);
66342542f5fSchristos
66442542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == buffer);
66542542f5fSchristos		assert(priv->gpu_bo == private->bo);
66642542f5fSchristos		assert(priv->gpu_bo->flush);
66742542f5fSchristos		assert(priv->pinned & PIN_DRI2);
66842542f5fSchristos		assert(priv->flush);
66942542f5fSchristos
67042542f5fSchristos		/* Undo the DRI markings on this pixmap */
67142542f5fSchristos		DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n",
67242542f5fSchristos		     __FUNCTION__,
67342542f5fSchristos		     pixmap->drawable.serialNumber,
67442542f5fSchristos		     pixmap == sna->front));
67542542f5fSchristos
67642542f5fSchristos		list_del(&priv->flush_list);
67742542f5fSchristos
67842542f5fSchristos		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
67942542f5fSchristos		priv->gpu_bo->flush = false;
68042542f5fSchristos		priv->pinned &= ~PIN_DRI2;
68142542f5fSchristos
68242542f5fSchristos		priv->flush = false;
68342542f5fSchristos		sna_accel_watch_flush(sna, -1);
68442542f5fSchristos
68542542f5fSchristos		sna_pixmap_set_buffer(pixmap, NULL);
68642542f5fSchristos		pixmap->drawable.pScreen->DestroyPixmap(pixmap);
68742542f5fSchristos	}
68842542f5fSchristos	assert(private->bo->flush == false);
68942542f5fSchristos
69042542f5fSchristos	kgem_bo_destroy(&sna->kgem, private->bo);
69142542f5fSchristos	free(buffer);
69242542f5fSchristos}
69342542f5fSchristos
69442542f5fSchristosstatic void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
69542542f5fSchristos{
69642542f5fSchristos	_sna_dri2_destroy_buffer(to_sna_from_drawable(draw), buffer);
69742542f5fSchristos}
69842542f5fSchristos
69942542f5fSchristosstatic DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer)
70042542f5fSchristos{
70142542f5fSchristos	get_private(buffer)->refcnt++;
70242542f5fSchristos	return buffer;
70342542f5fSchristos}
70442542f5fSchristos
70542542f5fSchristosstatic inline void damage(PixmapPtr pixmap, struct sna_pixmap *priv, RegionPtr region)
70642542f5fSchristos{
70742542f5fSchristos	assert(priv->gpu_bo);
70842542f5fSchristos	if (DAMAGE_IS_ALL(priv->gpu_damage))
70942542f5fSchristos		goto done;
71042542f5fSchristos
71142542f5fSchristos	if (region == NULL) {
71242542f5fSchristosdamage_all:
71342542f5fSchristos		priv->gpu_damage = _sna_damage_all(priv->gpu_damage,
71442542f5fSchristos						   pixmap->drawable.width,
71542542f5fSchristos						   pixmap->drawable.height);
71642542f5fSchristos		sna_damage_destroy(&priv->cpu_damage);
71742542f5fSchristos		list_del(&priv->flush_list);
71842542f5fSchristos	} else {
71942542f5fSchristos		sna_damage_subtract(&priv->cpu_damage, region);
72042542f5fSchristos		if (priv->cpu_damage == NULL)
72142542f5fSchristos			goto damage_all;
72242542f5fSchristos		sna_damage_add(&priv->gpu_damage, region);
72342542f5fSchristos	}
72442542f5fSchristosdone:
72542542f5fSchristos	priv->cpu = false;
72642542f5fSchristos	priv->clear = false;
72742542f5fSchristos}
72842542f5fSchristos
72942542f5fSchristosstatic void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
73042542f5fSchristos{
73142542f5fSchristos	struct sna *sna = to_sna_from_pixmap(pixmap);
73242542f5fSchristos	struct sna_pixmap *priv = sna_pixmap(pixmap);
73342542f5fSchristos	RegionRec region;
73442542f5fSchristos
73542542f5fSchristos	DBG(("%s: pixmap=%ld, handle=%d\n",
73642542f5fSchristos	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle));
73742542f5fSchristos
73842542f5fSchristos	assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
73942542f5fSchristos	assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
74042542f5fSchristos	assert(bo->proxy == NULL);
74142542f5fSchristos	assert(priv->pinned & PIN_DRI2);
74242542f5fSchristos	assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
74342542f5fSchristos	assert(priv->flush);
74442542f5fSchristos
74542542f5fSchristos	/* Post damage on the new front buffer so that listeners, such
74642542f5fSchristos	 * as DisplayLink know take a copy and shove it over the USB,
74742542f5fSchristos	 * also for software cursors and the like.
74842542f5fSchristos	 */
74942542f5fSchristos	region.extents.x1 = region.extents.y1 = 0;
75042542f5fSchristos	region.extents.x2 = pixmap->drawable.width;
75142542f5fSchristos	region.extents.y2 = pixmap->drawable.height;
75242542f5fSchristos	region.data = NULL;
75342542f5fSchristos	DamageRegionAppend(&pixmap->drawable, &region);
75442542f5fSchristos
75542542f5fSchristos	damage(pixmap, priv, NULL);
75642542f5fSchristos
75742542f5fSchristos	assert(bo->refcnt);
75842542f5fSchristos	if (priv->move_to_gpu)
75942542f5fSchristos		priv->move_to_gpu(sna, priv, 0);
76042542f5fSchristos	if (priv->gpu_bo != bo) {
76142542f5fSchristos		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
76242542f5fSchristos		priv->gpu_bo->flush = false;
76342542f5fSchristos		if (priv->cow)
76442542f5fSchristos			sna_pixmap_undo_cow(sna, priv, 0);
76542542f5fSchristos		if (priv->gpu_bo) {
76642542f5fSchristos			sna_pixmap_unmap(pixmap, priv);
76742542f5fSchristos			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
76842542f5fSchristos		}
76942542f5fSchristos		DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
77042542f5fSchristos		bo->flush = true;
77142542f5fSchristos		if (bo->exec)
77242542f5fSchristos			sna->kgem.flush = 1;
77342542f5fSchristos		priv->gpu_bo = ref(bo);
77442542f5fSchristos	}
77542542f5fSchristos	if (bo->domain != DOMAIN_GPU)
77642542f5fSchristos		bo->domain = DOMAIN_NONE;
77742542f5fSchristos	assert(bo->flush);
77842542f5fSchristos
77942542f5fSchristos	DamageRegionProcessPending(&pixmap->drawable);
78042542f5fSchristos}
78142542f5fSchristos
78242542f5fSchristosstatic void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync)
78342542f5fSchristos{
78442542f5fSchristos	struct drm_i915_gem_busy busy;
78542542f5fSchristos	int mode;
78642542f5fSchristos
78742542f5fSchristos	if (sna->kgem.gen < 060)
78842542f5fSchristos		return;
78942542f5fSchristos
79042542f5fSchristos	if (sync) {
79142542f5fSchristos		DBG(("%s: sync, force %s ring\n", __FUNCTION__,
79242542f5fSchristos		     sna->kgem.gen >= 070 ? "BLT" : "RENDER"));
79342542f5fSchristos		kgem_set_mode(&sna->kgem,
79442542f5fSchristos			      sna->kgem.gen >= 070 ? KGEM_BLT : KGEM_RENDER,
79542542f5fSchristos			      dst);
79642542f5fSchristos		return;
79742542f5fSchristos	}
79842542f5fSchristos
79942542f5fSchristos	if (DBG_FORCE_COPY != -1) {
80042542f5fSchristos		DBG(("%s: forcing %d\n", __FUNCTION__, DBG_FORCE_COPY));
80142542f5fSchristos		kgem_set_mode(&sna->kgem, DBG_FORCE_COPY, dst);
80242542f5fSchristos		return;
80342542f5fSchristos	}
80442542f5fSchristos
80542542f5fSchristos	if (sna->kgem.mode != KGEM_NONE) {
80642542f5fSchristos		DBG(("%s: busy, not switching\n", __FUNCTION__));
80742542f5fSchristos		return;
80842542f5fSchristos	}
80942542f5fSchristos
81042542f5fSchristos	VG_CLEAR(busy);
81142542f5fSchristos	busy.handle = src->handle;
81242542f5fSchristos	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
81342542f5fSchristos		return;
81442542f5fSchristos
81542542f5fSchristos	DBG(("%s: src handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy));
81642542f5fSchristos	if (busy.busy == 0) {
81742542f5fSchristos		__kgem_bo_clear_busy(src);
81842542f5fSchristos
81942542f5fSchristos		busy.handle = dst->handle;
82042542f5fSchristos		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
82142542f5fSchristos			return;
82242542f5fSchristos
82342542f5fSchristos		DBG(("%s: dst handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy));
82442542f5fSchristos		if (busy.busy == 0) {
82542542f5fSchristos			__kgem_bo_clear_busy(dst);
82642542f5fSchristos			DBG(("%s: src/dst is idle, using defaults\n", __FUNCTION__));
82742542f5fSchristos			return;
82842542f5fSchristos		}
82942542f5fSchristos	}
83042542f5fSchristos
83142542f5fSchristos	/* Sandybridge introduced a separate ring which it uses to
83242542f5fSchristos	 * perform blits. Switching rendering between rings incurs
83342542f5fSchristos	 * a stall as we wait upon the old ring to finish and
83442542f5fSchristos	 * flush its render cache before we can proceed on with
83542542f5fSchristos	 * the operation on the new ring.
83642542f5fSchristos	 *
83742542f5fSchristos	 * As this buffer, we presume, has just been written to by
83842542f5fSchristos	 * the DRI client using the RENDER ring, we want to perform
83942542f5fSchristos	 * our operation on the same ring, and ideally on the same
84042542f5fSchristos	 * ring as we will flip from (which should be the RENDER ring
84142542f5fSchristos	 * as well).
84242542f5fSchristos	 *
84342542f5fSchristos	 * The ultimate question is whether preserving the ring outweighs
84442542f5fSchristos	 * the cost of the query.
84542542f5fSchristos	 */
84642542f5fSchristos	mode = KGEM_RENDER;
84742542f5fSchristos	if (busy.busy & (0xfffe << 16))
84842542f5fSchristos		mode = KGEM_BLT;
84942542f5fSchristos	kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode);
85042542f5fSchristos	_kgem_set_mode(&sna->kgem, mode);
85142542f5fSchristos}
85242542f5fSchristos
85342542f5fSchristosstatic bool can_copy_cpu(struct sna *sna,
85442542f5fSchristos			 struct kgem_bo *src,
85542542f5fSchristos			 struct kgem_bo *dst)
85642542f5fSchristos{
85742542f5fSchristos	if (src->tiling != dst->tiling)
85842542f5fSchristos		return false;
85942542f5fSchristos
86042542f5fSchristos	if (src->pitch != dst->pitch)
86142542f5fSchristos		return false;
86242542f5fSchristos
86342542f5fSchristos	if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
86442542f5fSchristos		return false;
86542542f5fSchristos
86642542f5fSchristos	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true))
86742542f5fSchristos		return false;
86842542f5fSchristos
86942542f5fSchristos	DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
87042542f5fSchristos	return true;
87142542f5fSchristos}
87242542f5fSchristos
87342542f5fSchristosstatic void
87442542f5fSchristossna_dri2_copy_fallback(struct sna *sna,
87542542f5fSchristos		       const DrawableRec *draw,
87642542f5fSchristos		       struct kgem_bo *src_bo, int sx, int sy,
87742542f5fSchristos		       struct kgem_bo *dst_bo, int dx, int dy,
87842542f5fSchristos		       const BoxRec *box, int n)
87942542f5fSchristos{
88042542f5fSchristos	void *dst, *src;
88142542f5fSchristos	bool clipped;
88242542f5fSchristos
88342542f5fSchristos	clipped = (n > 1 ||
88442542f5fSchristos		   box->x1 + sx > 0 ||
88542542f5fSchristos		   box->y1 + sy > 0 ||
88642542f5fSchristos		   box->x2 + sx < draw->width ||
88742542f5fSchristos		   box->y2 + sy < draw->height);
88842542f5fSchristos
88942542f5fSchristos	dst = src = NULL;
89042542f5fSchristos	if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) {
89142542f5fSchristos		dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
89242542f5fSchristos		src = kgem_bo_map__cpu(&sna->kgem, src_bo);
89342542f5fSchristos	}
89442542f5fSchristos
89542542f5fSchristos	if (dst == NULL || src == NULL) {
89642542f5fSchristos		dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
89742542f5fSchristos		src = kgem_bo_map__gtt(&sna->kgem, src_bo);
89842542f5fSchristos		if (dst == NULL || src == NULL)
89942542f5fSchristos			return;
90042542f5fSchristos	} else {
90142542f5fSchristos		kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
90242542f5fSchristos		kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
90342542f5fSchristos	}
90442542f5fSchristos
90542542f5fSchristos	DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n",
90642542f5fSchristos	     __FUNCTION__, sx, sy, dx, dy, n));
90742542f5fSchristos
90842542f5fSchristos	if (sigtrap_get() == 0) {
90942542f5fSchristos		do {
91042542f5fSchristos			memcpy_blt(src, dst, draw->bitsPerPixel,
91142542f5fSchristos				   src_bo->pitch, dst_bo->pitch,
91242542f5fSchristos				   box->x1 + sx, box->y1 + sy,
91342542f5fSchristos				   box->x1 + dx, box->y1 + dy,
91442542f5fSchristos				   box->x2 - box->x1, box->y2 - box->y1);
91542542f5fSchristos			box++;
91642542f5fSchristos		} while (--n);
91742542f5fSchristos		sigtrap_put();
91842542f5fSchristos	}
91942542f5fSchristos}
92042542f5fSchristos
92142542f5fSchristosstatic bool is_front(int attachment)
92242542f5fSchristos{
92342542f5fSchristos	return attachment == DRI2BufferFrontLeft;
92442542f5fSchristos}
92542542f5fSchristos
92642542f5fSchristosstatic struct kgem_bo *
92742542f5fSchristos__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
92842542f5fSchristos		      DRI2BufferPtr src, DRI2BufferPtr dst,
92942542f5fSchristos		      bool sync)
93042542f5fSchristos{
93142542f5fSchristos	PixmapPtr pixmap = get_drawable_pixmap(draw);
93242542f5fSchristos	DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable;
93342542f5fSchristos	struct sna_dri2_private *src_priv = get_private(src);
93442542f5fSchristos	struct sna_dri2_private *dst_priv = get_private(dst);
93542542f5fSchristos	pixman_region16_t clip;
93642542f5fSchristos	struct kgem_bo *bo = NULL;
93742542f5fSchristos	struct kgem_bo *src_bo;
93842542f5fSchristos	struct kgem_bo *dst_bo;
93942542f5fSchristos	const BoxRec *boxes;
94042542f5fSchristos	int16_t dx, dy, sx, sy;
94142542f5fSchristos	int n;
94242542f5fSchristos
94342542f5fSchristos	/* To hide a stale DRI2Buffer, one may choose to substitute
94442542f5fSchristos	 * pixmap->gpu_bo instead of dst/src->bo, however you then run
94542542f5fSchristos	 * the risk of copying around invalid data. So either you may not
94642542f5fSchristos	 * see the results of the copy, or you may see the wrong pixels.
94742542f5fSchristos	 * Either way you eventually lose.
94842542f5fSchristos	 *
94942542f5fSchristos	 * We also have to be careful in case that the stale buffers are
95042542f5fSchristos	 * now attached to invalid (non-DRI) pixmaps.
95142542f5fSchristos	 */
95242542f5fSchristos
95342542f5fSchristos	assert(is_front(dst->attachment) || is_front(src->attachment));
95442542f5fSchristos	assert(dst->attachment != src->attachment);
95542542f5fSchristos
95642542f5fSchristos	clip.extents.x1 = draw->x;
95742542f5fSchristos	clip.extents.y1 = draw->y;
95842542f5fSchristos	clip.extents.x2 = draw->x + draw->width;
95942542f5fSchristos	clip.extents.y2 = draw->y + draw->height;
96042542f5fSchristos	clip.data = NULL;
96142542f5fSchristos
96242542f5fSchristos	if (region) {
96342542f5fSchristos		pixman_region_translate(region, draw->x, draw->y);
96442542f5fSchristos		pixman_region_intersect(&clip, &clip, region);
96542542f5fSchristos		region = &clip;
96642542f5fSchristos	}
96742542f5fSchristos
96842542f5fSchristos	if (clip.extents.x1 >= clip.extents.x2 ||
96942542f5fSchristos	    clip.extents.y1 >= clip.extents.y2) {
97042542f5fSchristos		DBG(("%s: all clipped\n", __FUNCTION__));
97142542f5fSchristos		return NULL;
97242542f5fSchristos	}
97342542f5fSchristos
97442542f5fSchristos	sx = sy = dx = dy = 0;
97542542f5fSchristos	if (is_front(dst->attachment)) {
97642542f5fSchristos		sx = -draw->x;
97742542f5fSchristos		sy = -draw->y;
97842542f5fSchristos	} else {
97942542f5fSchristos		dx = -draw->x;
98042542f5fSchristos		dy = -draw->y;
98142542f5fSchristos	}
98242542f5fSchristos	if (draw->type == DRAWABLE_WINDOW) {
98342542f5fSchristos		WindowPtr win = (WindowPtr)draw;
98442542f5fSchristos		int16_t tx, ty;
98542542f5fSchristos
98642542f5fSchristos		if (is_clipped(&win->clipList, draw)) {
98742542f5fSchristos			DBG(("%s: draw=(%d, %d), delta=(%d, %d), draw=(%d, %d),(%d, %d), clip.extents=(%d, %d), (%d, %d)\n",
98842542f5fSchristos			     __FUNCTION__, draw->x, draw->y,
98942542f5fSchristos			     get_drawable_dx(draw), get_drawable_dy(draw),
99042542f5fSchristos			     clip.extents.x1, clip.extents.y1,
99142542f5fSchristos			     clip.extents.x2, clip.extents.y2,
99242542f5fSchristos			     win->clipList.extents.x1, win->clipList.extents.y1,
99342542f5fSchristos			     win->clipList.extents.x2, win->clipList.extents.y2));
99442542f5fSchristos
99542542f5fSchristos			assert(region == NULL || region == &clip);
99642542f5fSchristos			pixman_region_intersect(&clip, &win->clipList, &clip);
99742542f5fSchristos			if (!pixman_region_not_empty(&clip)) {
99842542f5fSchristos				DBG(("%s: all clipped\n", __FUNCTION__));
99942542f5fSchristos				return NULL;
100042542f5fSchristos			}
100142542f5fSchristos
100242542f5fSchristos			region = &clip;
100342542f5fSchristos		}
100442542f5fSchristos
100542542f5fSchristos		if (get_drawable_deltas(draw, pixmap, &tx, &ty)) {
100642542f5fSchristos			if (is_front(dst->attachment)) {
100742542f5fSchristos				pixman_region_translate(region ?: &clip, tx, ty);
100842542f5fSchristos				sx -= tx;
100942542f5fSchristos				sy -= ty;
101042542f5fSchristos			} else {
101142542f5fSchristos				sx += tx;
101242542f5fSchristos				sy += ty;
101342542f5fSchristos			}
101442542f5fSchristos		}
101542542f5fSchristos	} else
101642542f5fSchristos		sync = false;
101742542f5fSchristos
101842542f5fSchristos	scratch.x = scratch.y = 0;
101942542f5fSchristos	scratch.width = scratch.height = 0;
102042542f5fSchristos	scratch.depth = draw->depth;
102142542f5fSchristos	scratch.bitsPerPixel = draw->bitsPerPixel;
102242542f5fSchristos
102342542f5fSchristos	src_bo = src_priv->bo;
102442542f5fSchristos	assert(src_bo->refcnt);
102542542f5fSchristos	if (is_front(src->attachment)) {
102642542f5fSchristos		struct sna_pixmap *priv;
102742542f5fSchristos
102842542f5fSchristos		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
102942542f5fSchristos		if (priv)
103042542f5fSchristos			src_bo = priv->gpu_bo;
103142542f5fSchristos		DBG(("%s: updated FrontLeft src_bo from handle=%d to handle=%d\n",
103242542f5fSchristos		     __FUNCTION__, src_priv->bo->handle, src_bo->handle));
103342542f5fSchristos		assert(src_bo->refcnt);
103442542f5fSchristos	} else {
103542542f5fSchristos		RegionRec source;
103642542f5fSchristos
103742542f5fSchristos		scratch.width = src_priv->size & 0xffff;
103842542f5fSchristos		scratch.height = src_priv->size >> 16;
103942542f5fSchristos		src_draw = &scratch;
104042542f5fSchristos
104142542f5fSchristos		DBG(("%s: source size %dx%d, region size %dx%d\n",
104242542f5fSchristos		     __FUNCTION__,
104342542f5fSchristos		     scratch.width, scratch.height,
104442542f5fSchristos		     clip.extents.x2 - clip.extents.x1,
104542542f5fSchristos		     clip.extents.y2 - clip.extents.y1));
104642542f5fSchristos
104742542f5fSchristos		source.extents.x1 = -sx;
104842542f5fSchristos		source.extents.y1 = -sy;
104942542f5fSchristos		source.extents.x2 = source.extents.x1 + scratch.width;
105042542f5fSchristos		source.extents.y2 = source.extents.y1 + scratch.height;
105142542f5fSchristos		source.data = NULL;
105242542f5fSchristos
105342542f5fSchristos		assert(region == NULL || region == &clip);
105442542f5fSchristos		pixman_region_intersect(&clip, &clip, &source);
105542542f5fSchristos
105642542f5fSchristos	}
105742542f5fSchristos
105842542f5fSchristos	dst_bo = dst_priv->bo;
105942542f5fSchristos	assert(dst_bo->refcnt);
106042542f5fSchristos	if (is_front(dst->attachment)) {
106142542f5fSchristos		struct sna_pixmap *priv;
106242542f5fSchristos		unsigned int flags;
106342542f5fSchristos
106442542f5fSchristos		flags = MOVE_WRITE | __MOVE_FORCE;
106542542f5fSchristos		if (clip.data)
106642542f5fSchristos			flags |= MOVE_READ;
106742542f5fSchristos
106842542f5fSchristos		assert(region == NULL || region == &clip);
106942542f5fSchristos		priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags);
107042542f5fSchristos		if (priv) {
107142542f5fSchristos			damage(pixmap, priv, region);
107242542f5fSchristos			dst_bo = priv->gpu_bo;
107342542f5fSchristos		}
107442542f5fSchristos		DBG(("%s: updated FrontLeft dst_bo from handle=%d to handle=%d\n",
107542542f5fSchristos		     __FUNCTION__, dst_priv->bo->handle, dst_bo->handle));
107642542f5fSchristos		assert(dst_bo->refcnt);
107742542f5fSchristos	} else {
107842542f5fSchristos		RegionRec target;
107942542f5fSchristos
108042542f5fSchristos		scratch.width = dst_priv->size & 0xffff;
108142542f5fSchristos		scratch.height = dst_priv->size >> 16;
108242542f5fSchristos		dst_draw = &scratch;
108342542f5fSchristos
108442542f5fSchristos		DBG(("%s: target size %dx%d, region size %dx%d\n",
108542542f5fSchristos		     __FUNCTION__,
108642542f5fSchristos		     scratch.width, scratch.height,
108742542f5fSchristos		     clip.extents.x2 - clip.extents.x1,
108842542f5fSchristos		     clip.extents.y2 - clip.extents.y1));
108942542f5fSchristos
109042542f5fSchristos		target.extents.x1 = -dx;
109142542f5fSchristos		target.extents.y1 = -dy;
109242542f5fSchristos		target.extents.x2 = target.extents.x1 + scratch.width;
109342542f5fSchristos		target.extents.y2 = target.extents.y1 + scratch.height;
109442542f5fSchristos		target.data = NULL;
109542542f5fSchristos
109642542f5fSchristos		assert(region == NULL || region == &clip);
109742542f5fSchristos		pixman_region_intersect(&clip, &clip, &target);
109842542f5fSchristos
109942542f5fSchristos		sync = false;
110042542f5fSchristos	}
110142542f5fSchristos
110242542f5fSchristos	if (!wedged(sna)) {
110342542f5fSchristos		xf86CrtcPtr crtc;
110442542f5fSchristos
110542542f5fSchristos		crtc = NULL;
110642542f5fSchristos		if (sync && sna_pixmap_is_scanout(sna, pixmap))
110742542f5fSchristos			crtc = sna_covering_crtc(sna, &clip.extents, NULL);
110842542f5fSchristos		sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL);
110942542f5fSchristos
111042542f5fSchristos		sync = (crtc != NULL&&
111142542f5fSchristos			sna_wait_for_scanline(sna, pixmap, crtc,
111242542f5fSchristos					      &clip.extents));
111342542f5fSchristos	}
111442542f5fSchristos
111542542f5fSchristos	if (region) {
111642542f5fSchristos		boxes = region_rects(region);
111742542f5fSchristos		n = region_num_rects(region);
111842542f5fSchristos		assert(n);
111942542f5fSchristos	} else {
112042542f5fSchristos		region = &clip;
112142542f5fSchristos		boxes = &clip.extents;
112242542f5fSchristos		n = 1;
112342542f5fSchristos	}
112442542f5fSchristos	DamageRegionAppend(&pixmap->drawable, region);
112542542f5fSchristos
112642542f5fSchristos	if (wedged(sna)) {
112742542f5fSchristosfallback:
112842542f5fSchristos		sna_dri2_copy_fallback(sna, src_draw,
112942542f5fSchristos				      src_bo, sx, sy,
113042542f5fSchristos				      dst_bo, dx, dy,
113142542f5fSchristos				      boxes, n);
113242542f5fSchristos	} else {
113342542f5fSchristos		unsigned flags;
113442542f5fSchristos
113542542f5fSchristos		DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n",
113642542f5fSchristos		     __FUNCTION__,
113742542f5fSchristos		     boxes[0].x1, boxes[0].y1,
113842542f5fSchristos		     boxes[0].x2, boxes[0].y2,
113942542f5fSchristos		     n, sx, sy, dx, dy));
114042542f5fSchristos
114142542f5fSchristos		flags = COPY_LAST;
114242542f5fSchristos		if (sync)
114342542f5fSchristos			flags |= COPY_SYNC;
114442542f5fSchristos		if (!sna->render.copy_boxes(sna, GXcopy,
114542542f5fSchristos					    src_draw, src_bo, sx, sy,
114642542f5fSchristos					    dst_draw, dst_bo, dx, dy,
114742542f5fSchristos					    boxes, n, flags))
114842542f5fSchristos			goto fallback;
114942542f5fSchristos
115042542f5fSchristos		DBG(("%s: flushing? %d\n", __FUNCTION__, sync));
115142542f5fSchristos		if (sync) { /* STAT! */
115242542f5fSchristos			struct kgem_request *rq = sna->kgem.next_request;
115342542f5fSchristos			kgem_submit(&sna->kgem);
115442542f5fSchristos			if (rq->bo) {
115542542f5fSchristos				bo = ref(rq->bo);
115642542f5fSchristos				DBG(("%s: recording sync fence handle=%d\n", __FUNCTION__, bo->handle));
115742542f5fSchristos			}
115842542f5fSchristos		}
115942542f5fSchristos	}
116042542f5fSchristos
116142542f5fSchristos	DamageRegionProcessPending(&pixmap->drawable);
116242542f5fSchristos
116342542f5fSchristos	if (clip.data)
116442542f5fSchristos		pixman_region_fini(&clip);
116542542f5fSchristos
116642542f5fSchristos	return bo;
116742542f5fSchristos}
116842542f5fSchristos
116942542f5fSchristosstatic void
117042542f5fSchristossna_dri2_copy_region(DrawablePtr draw,
117142542f5fSchristos		     RegionPtr region,
117242542f5fSchristos		     DRI2BufferPtr dst,
117342542f5fSchristos		     DRI2BufferPtr src)
117442542f5fSchristos{
117542542f5fSchristos	PixmapPtr pixmap = get_drawable_pixmap(draw);
117642542f5fSchristos	struct sna *sna = to_sna_from_pixmap(pixmap);
117742542f5fSchristos
117842542f5fSchristos	DBG(("%s: pixmap=%ld, src=%u (refs=%d/%d, flush=%d, attach=%d) , dst=%u (refs=%d/%d, flush=%d, attach=%d)\n",
117942542f5fSchristos	     __FUNCTION__,
118042542f5fSchristos	     pixmap->drawable.serialNumber,
118142542f5fSchristos	     get_private(src)->bo->handle,
118242542f5fSchristos	     get_private(src)->refcnt,
118342542f5fSchristos	     get_private(src)->bo->refcnt,
118442542f5fSchristos	     get_private(src)->bo->flush,
118542542f5fSchristos	     src->attachment,
118642542f5fSchristos	     get_private(dst)->bo->handle,
118742542f5fSchristos	     get_private(dst)->refcnt,
118842542f5fSchristos	     get_private(dst)->bo->refcnt,
118942542f5fSchristos	     get_private(dst)->bo->flush,
119042542f5fSchristos	     dst->attachment));
119142542f5fSchristos
119242542f5fSchristos	assert(src != dst);
119342542f5fSchristos
119442542f5fSchristos	assert(get_private(src)->refcnt);
119542542f5fSchristos	assert(get_private(dst)->refcnt);
119642542f5fSchristos
119742542f5fSchristos	assert(get_private(src)->bo->refcnt);
119842542f5fSchristos	assert(get_private(dst)->bo->refcnt);
119942542f5fSchristos
120042542f5fSchristos	DBG(("%s: region (%d, %d), (%d, %d) x %d\n",
120142542f5fSchristos	     __FUNCTION__,
120242542f5fSchristos	     region->extents.x1, region->extents.y1,
120342542f5fSchristos	     region->extents.x2, region->extents.y2,
120442542f5fSchristos	     region_num_rects(region)));
120542542f5fSchristos
120642542f5fSchristos	__sna_dri2_copy_region(sna, draw, region, src, dst, false);
120742542f5fSchristos}
120842542f5fSchristos
120942542f5fSchristosinline static uint32_t pipe_select(int pipe)
121042542f5fSchristos{
121142542f5fSchristos	/* The third pipe was introduced with IvyBridge long after
121242542f5fSchristos	 * multiple pipe support was added to the kernel, hence
121342542f5fSchristos	 * we can safely ignore the capability check - if we have more
121442542f5fSchristos	 * than two pipes, we can assume that they are fully supported.
121542542f5fSchristos	 */
121642542f5fSchristos	if (pipe > 1)
121742542f5fSchristos		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
121842542f5fSchristos	else if (pipe > 0)
121942542f5fSchristos		return DRM_VBLANK_SECONDARY;
122042542f5fSchristos	else
122142542f5fSchristos		return 0;
122242542f5fSchristos}
122342542f5fSchristos
122442542f5fSchristosstatic inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe)
122542542f5fSchristos{
122642542f5fSchristos	DBG(("%s(pipe=%d, waiting until seq=%u%s)\n",
122742542f5fSchristos	     __FUNCTION__, pipe, vbl->request.sequence,
122842542f5fSchristos	     vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : ""));
122942542f5fSchristos	assert(pipe != -1);
123042542f5fSchristos
123142542f5fSchristos	vbl->request.type |= pipe_select(pipe);
123242542f5fSchristos	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
123342542f5fSchristos}
123442542f5fSchristos
123542542f5fSchristos#if DRI2INFOREC_VERSION >= 4
123642542f5fSchristos
123742542f5fSchristosstatic void dri2_window_attach(WindowPtr win, struct dri2_window *priv)
123842542f5fSchristos{
123942542f5fSchristos	assert(win->drawable.type == DRAWABLE_WINDOW);
124042542f5fSchristos	assert(dri2_window(win) == NULL);
124142542f5fSchristos	((void **)__get_private(win, sna_window_key))[1] = priv;
124242542f5fSchristos	assert(dri2_window(win) == priv);
124342542f5fSchristos}
124442542f5fSchristos
124542542f5fSchristosstatic uint64_t
124642542f5fSchristosdraw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
124742542f5fSchristos{
124842542f5fSchristos	struct dri2_window *priv;
124942542f5fSchristos
125042542f5fSchristos	if (draw->type != DRAWABLE_WINDOW)
125142542f5fSchristos		return msc;
125242542f5fSchristos
125342542f5fSchristos	priv = dri2_window((WindowPtr)draw);
125442542f5fSchristos	if (priv == NULL) {
125542542f5fSchristos		priv = malloc(sizeof(*priv));
125642542f5fSchristos		if (priv != NULL) {
125742542f5fSchristos			priv->front = NULL;
125842542f5fSchristos			priv->crtc = crtc;
125942542f5fSchristos			priv->msc_delta = 0;
126042542f5fSchristos			priv->chain = NULL;
126142542f5fSchristos			dri2_window_attach((WindowPtr)draw, priv);
126242542f5fSchristos		}
126342542f5fSchristos	} else {
126442542f5fSchristos		if (priv->crtc != crtc) {
126542542f5fSchristos			const struct ust_msc *last = sna_crtc_last_swap(priv->crtc);
126642542f5fSchristos			const struct ust_msc *this = sna_crtc_last_swap(crtc);
126742542f5fSchristos			DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
126842542f5fSchristos			     __FUNCTION__,
126942542f5fSchristos			     sna_crtc_to_pipe(priv->crtc), (long long)last->msc,
127042542f5fSchristos			     sna_crtc_to_pipe(crtc), (long long)this->msc,
127142542f5fSchristos			     (long long)(priv->msc_delta + this->msc - last->msc)));
127242542f5fSchristos			priv->msc_delta += this->msc - last->msc;
127342542f5fSchristos			priv->crtc = crtc;
127442542f5fSchristos		}
127542542f5fSchristos		msc -= priv->msc_delta;
127642542f5fSchristos	}
127742542f5fSchristos	return  msc;
127842542f5fSchristos}
127942542f5fSchristos
128042542f5fSchristosstatic uint32_t
128142542f5fSchristosdraw_target_seq(DrawablePtr draw, uint64_t msc)
128242542f5fSchristos{
128342542f5fSchristos	struct dri2_window *priv = dri2_window((WindowPtr)draw);
128442542f5fSchristos	if (priv == NULL)
128542542f5fSchristos		return msc;
128642542f5fSchristos	DBG(("%s: converting target_msc=%llu to seq %u\n",
128742542f5fSchristos	     __FUNCTION__, (long long)msc, (unsigned)(msc + priv->msc_delta)));
128842542f5fSchristos	return msc + priv->msc_delta;
128942542f5fSchristos}
129042542f5fSchristos
129142542f5fSchristosstatic xf86CrtcPtr
129242542f5fSchristossna_dri2_get_crtc(DrawablePtr draw)
129342542f5fSchristos{
129442542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
129542542f5fSchristos	BoxRec box;
129642542f5fSchristos
129742542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
129842542f5fSchristos		return NULL;
129942542f5fSchristos
130042542f5fSchristos	box.x1 = draw->x;
130142542f5fSchristos	box.y1 = draw->y;
130242542f5fSchristos	box.x2 = box.x1 + draw->width;
130342542f5fSchristos	box.y2 = box.y1 + draw->height;
130442542f5fSchristos
130542542f5fSchristos	/* Make sure the CRTC is valid and this is the real front buffer */
130642542f5fSchristos	return sna_covering_crtc(sna, &box, NULL);
130742542f5fSchristos}
130842542f5fSchristos
130942542f5fSchristosstatic void
131042542f5fSchristossna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
131142542f5fSchristos{
131242542f5fSchristos	struct dri2_window *priv;
131342542f5fSchristos	struct sna_dri2_event *chain;
131442542f5fSchristos
131542542f5fSchristos	assert(win->drawable.type == DRAWABLE_WINDOW);
131642542f5fSchristos	DBG(("%s: remove[%p] from window %ld, active? %d\n",
131742542f5fSchristos	     __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
131842542f5fSchristos
131942542f5fSchristos	priv = dri2_window(win);
132042542f5fSchristos	assert(priv);
132142542f5fSchristos	assert(priv->chain != NULL);
132242542f5fSchristos
132342542f5fSchristos	if (priv->chain == info) {
132442542f5fSchristos		priv->chain = info->chain;
132542542f5fSchristos		return;
132642542f5fSchristos	}
132742542f5fSchristos
132842542f5fSchristos	chain = priv->chain;
132942542f5fSchristos	while (chain->chain != info)
133042542f5fSchristos		chain = chain->chain;
133142542f5fSchristos	assert(chain != info);
133242542f5fSchristos	assert(info->chain != chain);
133342542f5fSchristos	chain->chain = info->chain;
133442542f5fSchristos}
133542542f5fSchristos
133642542f5fSchristosstatic void
133742542f5fSchristossna_dri2_event_free(struct sna *sna,
133842542f5fSchristos		    struct sna_dri2_event *info)
133942542f5fSchristos{
134042542f5fSchristos	DrawablePtr draw = info->draw;
134142542f5fSchristos
134242542f5fSchristos	DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
134342542f5fSchristos	if (draw && draw->type == DRAWABLE_WINDOW)
134442542f5fSchristos		sna_dri2_remove_event((WindowPtr)draw, info);
134542542f5fSchristos
134642542f5fSchristos	_sna_dri2_destroy_buffer(sna, info->front);
134742542f5fSchristos	_sna_dri2_destroy_buffer(sna, info->back);
134842542f5fSchristos
134942542f5fSchristos	while (!list_is_empty(&info->cache)) {
135042542f5fSchristos		struct dri_bo *c;
135142542f5fSchristos
135242542f5fSchristos		c = list_first_entry(&info->cache, struct dri_bo, link);
135342542f5fSchristos		list_del(&c->link);
135442542f5fSchristos
135542542f5fSchristos		DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
135642542f5fSchristos		if (c->bo)
135742542f5fSchristos			kgem_bo_destroy(&sna->kgem, c->bo);
135842542f5fSchristos
135942542f5fSchristos		free(c);
136042542f5fSchristos	}
136142542f5fSchristos
136242542f5fSchristos	if (info->bo) {
136342542f5fSchristos		DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
136442542f5fSchristos		kgem_bo_destroy(&sna->kgem, info->bo);
136542542f5fSchristos	}
136642542f5fSchristos
136742542f5fSchristos	_list_del(&info->link);
136842542f5fSchristos	free(info);
136942542f5fSchristos}
137042542f5fSchristos
137142542f5fSchristosstatic void
137242542f5fSchristossna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
137342542f5fSchristos{
137442542f5fSchristos	NewClientInfoRec *clientinfo = data;
137542542f5fSchristos	ClientPtr client = clientinfo->client;
137642542f5fSchristos	struct sna_client *priv = sna_client(client);
137742542f5fSchristos	struct sna *sna = closure;
137842542f5fSchristos
137942542f5fSchristos	if (priv->events.next == NULL)
138042542f5fSchristos		return;
138142542f5fSchristos
138242542f5fSchristos	if (client->clientState != ClientStateGone)
138342542f5fSchristos		return;
138442542f5fSchristos
138542542f5fSchristos	DBG(("%s(active?=%d)\n", __FUNCTION__,
138642542f5fSchristos	     !list_is_empty(&priv->events)));
138742542f5fSchristos
138842542f5fSchristos	while (!list_is_empty(&priv->events)) {
138942542f5fSchristos		struct sna_dri2_event *event;
139042542f5fSchristos
139142542f5fSchristos		event = list_first_entry(&priv->events, struct sna_dri2_event, link);
139242542f5fSchristos		assert(event->client == client);
139342542f5fSchristos
139442542f5fSchristos		if (event->queued) {
139542542f5fSchristos			if (event->draw)
139642542f5fSchristos				sna_dri2_remove_event((WindowPtr)event->draw,
139742542f5fSchristos						      event);
139842542f5fSchristos			event->client = NULL;
139942542f5fSchristos			event->draw = NULL;
140042542f5fSchristos			list_del(&event->link);
140142542f5fSchristos		} else
140242542f5fSchristos			sna_dri2_event_free(sna, event);
140342542f5fSchristos	}
140442542f5fSchristos
140542542f5fSchristos	if (--sna->dri2.client_count == 0)
140642542f5fSchristos		DeleteCallback(&ClientStateCallback, sna_dri2_client_gone, sna);
140742542f5fSchristos}
140842542f5fSchristos
140942542f5fSchristosstatic bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, ClientPtr client)
141042542f5fSchristos{
141142542f5fSchristos	struct sna_client *priv = sna_client(client);
141242542f5fSchristos
141342542f5fSchristos	if (priv->events.next == NULL) {
141442542f5fSchristos		if (sna->dri2.client_count++ == 0 &&
141542542f5fSchristos		    !AddCallback(&ClientStateCallback, sna_dri2_client_gone, sna))
141642542f5fSchristos			return false;
141742542f5fSchristos
141842542f5fSchristos		list_init(&priv->events);
141942542f5fSchristos	}
142042542f5fSchristos
142142542f5fSchristos	list_add(&info->link, &priv->events);
142242542f5fSchristos	info->client = client;
142342542f5fSchristos	return true;
142442542f5fSchristos}
142542542f5fSchristos
142642542f5fSchristosstatic struct sna_dri2_event *
142742542f5fSchristossna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
142842542f5fSchristos{
142942542f5fSchristos	struct dri2_window *priv;
143042542f5fSchristos	struct sna_dri2_event *info, *chain;
143142542f5fSchristos
143242542f5fSchristos	assert(draw->type == DRAWABLE_WINDOW);
143342542f5fSchristos	DBG(("%s: adding event to window %ld)\n",
143442542f5fSchristos	     __FUNCTION__, (long)draw->id));
143542542f5fSchristos
143642542f5fSchristos	priv = dri2_window((WindowPtr)draw);
143742542f5fSchristos	if (priv == NULL)
143842542f5fSchristos		return NULL;
143942542f5fSchristos
144042542f5fSchristos	info = calloc(1, sizeof(struct sna_dri2_event));
144142542f5fSchristos	if (info == NULL)
144242542f5fSchristos		return NULL;
144342542f5fSchristos
144442542f5fSchristos	list_init(&info->cache);
144542542f5fSchristos	info->draw = draw;
144642542f5fSchristos	info->crtc = priv->crtc;
144742542f5fSchristos	info->pipe = sna_crtc_to_pipe(priv->crtc);
144842542f5fSchristos
144942542f5fSchristos	if (!add_event_to_client(info, sna, client)) {
145042542f5fSchristos		free(info);
145142542f5fSchristos		return NULL;
145242542f5fSchristos	}
145342542f5fSchristos
145442542f5fSchristos	assert(priv->chain != info);
145542542f5fSchristos
145642542f5fSchristos	if (priv->chain == NULL) {
145742542f5fSchristos		priv->chain = info;
145842542f5fSchristos		return info;
145942542f5fSchristos	}
146042542f5fSchristos
146142542f5fSchristos	chain = priv->chain;
146242542f5fSchristos	while (chain->chain != NULL)
146342542f5fSchristos		chain = chain->chain;
146442542f5fSchristos
146542542f5fSchristos	assert(chain != info);
146642542f5fSchristos	chain->chain = info;
146742542f5fSchristos	return info;
146842542f5fSchristos}
146942542f5fSchristos
147042542f5fSchristosvoid sna_dri2_destroy_window(WindowPtr win)
147142542f5fSchristos{
147242542f5fSchristos	struct sna *sna;
147342542f5fSchristos	struct dri2_window *priv;
147442542f5fSchristos
147542542f5fSchristos	priv = dri2_window(win);
147642542f5fSchristos	if (priv == NULL)
147742542f5fSchristos		return;
147842542f5fSchristos
147942542f5fSchristos	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber));
148042542f5fSchristos	sna = to_sna_from_drawable(&win->drawable);
148142542f5fSchristos
148242542f5fSchristos	if (priv->front) {
148342542f5fSchristos		assert(priv->crtc);
148442542f5fSchristos		sna_shadow_unset_crtc(sna, priv->crtc);
148542542f5fSchristos		_sna_dri2_destroy_buffer(sna, priv->front);
148642542f5fSchristos	}
148742542f5fSchristos
148842542f5fSchristos	if (priv->chain) {
148942542f5fSchristos		struct sna_dri2_event *info, *chain;
149042542f5fSchristos
149142542f5fSchristos		DBG(("%s: freeing chain\n", __FUNCTION__));
149242542f5fSchristos
149342542f5fSchristos		chain = priv->chain;
149442542f5fSchristos		while ((info = chain)) {
149542542f5fSchristos			info->draw = NULL;
149642542f5fSchristos			info->client = NULL;
149742542f5fSchristos
149842542f5fSchristos			chain = info->chain;
149942542f5fSchristos			info->chain = NULL;
150042542f5fSchristos
150142542f5fSchristos			if (!info->queued)
150242542f5fSchristos				sna_dri2_event_free(sna, info);
150342542f5fSchristos		}
150442542f5fSchristos	}
150542542f5fSchristos
150642542f5fSchristos	free(priv);
150742542f5fSchristos}
150842542f5fSchristos
150942542f5fSchristosstatic void
151042542f5fSchristossna_dri2_flip_handler(struct sna *sna,
151142542f5fSchristos		      struct drm_event_vblank *event,
151242542f5fSchristos		      void *data)
151342542f5fSchristos{
151442542f5fSchristos	DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence));
151542542f5fSchristos	sna_dri2_flip_event(sna, data);
151642542f5fSchristos}
151742542f5fSchristos
151842542f5fSchristosstatic bool
151942542f5fSchristossna_dri2_flip(struct sna *sna, struct sna_dri2_event *info)
152042542f5fSchristos{
152142542f5fSchristos	struct kgem_bo *bo = get_private(info->back)->bo;
152242542f5fSchristos	struct kgem_bo *tmp_bo;
152342542f5fSchristos	uint32_t tmp_name;
152442542f5fSchristos
152542542f5fSchristos	DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
152642542f5fSchristos
152742542f5fSchristos	assert(sna_pixmap_get_buffer(sna->front) == info->front);
152842542f5fSchristos	assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
152942542f5fSchristos	assert(bo->refcnt);
153042542f5fSchristos
153142542f5fSchristos	if (!sna_page_flip(sna, bo, sna_dri2_flip_handler,
153242542f5fSchristos			   info->type == FLIP_ASYNC ? NULL : info))
153342542f5fSchristos		return false;
153442542f5fSchristos
153542542f5fSchristos	assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
153642542f5fSchristos	if (info->type != FLIP_ASYNC)
153742542f5fSchristos		sna->dri2.flip_pending = info;
153842542f5fSchristos
153942542f5fSchristos	DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
154042542f5fSchristos	     __FUNCTION__, bo->handle,
154142542f5fSchristos	     get_private(info->front)->bo->handle, info->front->name,
154242542f5fSchristos	     get_private(info->back)->bo->handle, info->back->name));
154342542f5fSchristos
154442542f5fSchristos	tmp_bo = get_private(info->front)->bo;
154542542f5fSchristos	tmp_name = info->front->name;
154642542f5fSchristos
154742542f5fSchristos	set_bo(sna->front, bo);
154842542f5fSchristos
154942542f5fSchristos	info->front->name = info->back->name;
155042542f5fSchristos	get_private(info->front)->bo = bo;
155142542f5fSchristos
155242542f5fSchristos	info->back->name = tmp_name;
155342542f5fSchristos	get_private(info->back)->bo = tmp_bo;
155442542f5fSchristos	get_private(info->back)->stale = true;
155542542f5fSchristos
155642542f5fSchristos	assert(get_private(info->front)->bo->refcnt);
155742542f5fSchristos	assert(get_private(info->back)->bo->refcnt);
155842542f5fSchristos	assert(get_private(info->front)->bo != get_private(info->back)->bo);
155942542f5fSchristos
156042542f5fSchristos	info->queued = true;
156142542f5fSchristos	return true;
156242542f5fSchristos}
156342542f5fSchristos
156442542f5fSchristosstatic bool
156542542f5fSchristoscan_flip(struct sna * sna,
156642542f5fSchristos	 DrawablePtr draw,
156742542f5fSchristos	 DRI2BufferPtr front,
156842542f5fSchristos	 DRI2BufferPtr back,
156942542f5fSchristos	 xf86CrtcPtr crtc)
157042542f5fSchristos{
157142542f5fSchristos	WindowPtr win = (WindowPtr)draw;
157242542f5fSchristos	PixmapPtr pixmap;
157342542f5fSchristos
157442542f5fSchristos	assert((sna->flags & SNA_NO_WAIT) == 0);
157542542f5fSchristos
157642542f5fSchristos	if (!DBG_CAN_FLIP)
157742542f5fSchristos		return false;
157842542f5fSchristos
157942542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
158042542f5fSchristos		return false;
158142542f5fSchristos
158242542f5fSchristos	if (!sna->mode.front_active) {
158342542f5fSchristos		DBG(("%s: no, active CRTC\n", __FUNCTION__));
158442542f5fSchristos		return false;
158542542f5fSchristos	}
158642542f5fSchristos
158742542f5fSchristos	assert(sna->scrn->vtSema);
158842542f5fSchristos
158942542f5fSchristos	if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) {
159042542f5fSchristos		DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
159142542f5fSchristos		return false;
159242542f5fSchristos	}
159342542f5fSchristos
159442542f5fSchristos	if (front->format != back->format) {
159542542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
159642542f5fSchristos		     __FUNCTION__, front->format, back->format));
159742542f5fSchristos		return false;
159842542f5fSchristos	}
159942542f5fSchristos
160042542f5fSchristos	if (sna->mode.shadow_active) {
160142542f5fSchristos		DBG(("%s: no, shadow enabled\n", __FUNCTION__));
160242542f5fSchristos		return false;
160342542f5fSchristos	}
160442542f5fSchristos
160542542f5fSchristos	if (!sna_crtc_is_on(crtc)) {
160642542f5fSchristos		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc)));
160742542f5fSchristos		return false;
160842542f5fSchristos	}
160942542f5fSchristos
161042542f5fSchristos	pixmap = get_window_pixmap(win);
161142542f5fSchristos	if (pixmap != sna->front) {
161242542f5fSchristos		DBG(("%s: no, window (pixmap=%ld) is not attached to the front buffer (pixmap=%ld)\n",
161342542f5fSchristos		     __FUNCTION__, pixmap->drawable.serialNumber, sna->front->drawable.serialNumber));
161442542f5fSchristos		return false;
161542542f5fSchristos	}
161642542f5fSchristos
161742542f5fSchristos	if (sna_pixmap_get_buffer(pixmap) != front) {
161842542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n",
161942542f5fSchristos		     __FUNCTION__, front->name,
162042542f5fSchristos		     sna_pixmap_get_buffer(pixmap) ? ((DRI2BufferPtr)sna_pixmap_get_buffer(pixmap))->name : 0,
162142542f5fSchristos		     pixmap->drawable.serialNumber));
162242542f5fSchristos		return false;
162342542f5fSchristos	}
162442542f5fSchristos
162542542f5fSchristos	assert(get_private(front)->pixmap == sna->front);
162642542f5fSchristos	assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo);
162742542f5fSchristos
162842542f5fSchristos	if (!get_private(back)->bo->scanout) {
162942542f5fSchristos		DBG(("%s: no, DRI2 drawable was too small at time of creation)\n",
163042542f5fSchristos		     __FUNCTION__));
163142542f5fSchristos		return false;
163242542f5fSchristos	}
163342542f5fSchristos
163442542f5fSchristos	if (get_private(back)->size != get_private(front)->size) {
163542542f5fSchristos		DBG(("%s: no, DRI2 drawable does not fit into scanout\n",
163642542f5fSchristos		     __FUNCTION__));
163742542f5fSchristos		return false;
163842542f5fSchristos	}
163942542f5fSchristos
164042542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
164142542f5fSchristos	     __FUNCTION__,
164242542f5fSchristos	     win->drawable.width, win->drawable.height,
164342542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
164442542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
164542542f5fSchristos	     region_num_rects(&win->clipList)));
164642542f5fSchristos	if (!RegionEqual(&win->clipList, &draw->pScreen->root->winSize)) {
164742542f5fSchristos		DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n",
164842542f5fSchristos		     __FUNCTION__,
164942542f5fSchristos		     win->clipList.extents.x1,
165042542f5fSchristos		     win->clipList.extents.y1,
165142542f5fSchristos		     win->clipList.extents.x2,
165242542f5fSchristos		     win->clipList.extents.y2,
165342542f5fSchristos		     draw->pScreen->root->winSize.extents.x1,
165442542f5fSchristos		     draw->pScreen->root->winSize.extents.y1,
165542542f5fSchristos		     draw->pScreen->root->winSize.extents.x2,
165642542f5fSchristos		     draw->pScreen->root->winSize.extents.y2));
165742542f5fSchristos		return false;
165842542f5fSchristos	}
165942542f5fSchristos
166042542f5fSchristos	if (draw->x != 0 || draw->y != 0 ||
166142542f5fSchristos#ifdef COMPOSITE
166242542f5fSchristos	    draw->x != pixmap->screen_x ||
166342542f5fSchristos	    draw->y != pixmap->screen_y ||
166442542f5fSchristos#endif
166542542f5fSchristos	    draw->width != pixmap->drawable.width ||
166642542f5fSchristos	    draw->height != pixmap->drawable.height) {
166742542f5fSchristos		DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n",
166842542f5fSchristos		     __FUNCTION__,
166942542f5fSchristos		     draw->width, draw->height,
167042542f5fSchristos		     pixmap->drawable.width,
167142542f5fSchristos		     pixmap->drawable.height));
167242542f5fSchristos		return false;
167342542f5fSchristos	}
167442542f5fSchristos
167542542f5fSchristos	/* prevent an implicit tiling mode change */
167642542f5fSchristos	if (get_private(back)->bo->tiling > I915_TILING_X) {
167742542f5fSchristos		DBG(("%s -- no, tiling mismatch: front %d, back=%d, want-tiled?=%d\n",
167842542f5fSchristos		     __FUNCTION__,
167942542f5fSchristos		     get_private(front)->bo->tiling,
168042542f5fSchristos		     get_private(back)->bo->tiling,
168142542f5fSchristos		     !!(sna->flags & SNA_LINEAR_FB)));
168242542f5fSchristos		return false;
168342542f5fSchristos	}
168442542f5fSchristos
168542542f5fSchristos	if (get_private(front)->bo->pitch != get_private(back)->bo->pitch) {
168642542f5fSchristos		DBG(("%s -- no, pitch mismatch: front %d, back=%d\n",
168742542f5fSchristos		     __FUNCTION__,
168842542f5fSchristos		     get_private(front)->bo->pitch,
168942542f5fSchristos		     get_private(back)->bo->pitch));
169042542f5fSchristos		return false;
169142542f5fSchristos	}
169242542f5fSchristos
169342542f5fSchristos	if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) {
169442542f5fSchristos		DBG(("%s -- no, pinned: front %x\n",
169542542f5fSchristos		     __FUNCTION__, sna_pixmap(pixmap)->pinned));
169642542f5fSchristos		return false;
169742542f5fSchristos	}
169842542f5fSchristos
169942542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
170042542f5fSchristos	assert(dri2_window(win)->front == NULL);
170142542f5fSchristos	return true;
170242542f5fSchristos}
170342542f5fSchristos
170442542f5fSchristosstatic bool
170542542f5fSchristoscan_xchg(struct sna * sna,
170642542f5fSchristos	 DrawablePtr draw,
170742542f5fSchristos	 DRI2BufferPtr front,
170842542f5fSchristos	 DRI2BufferPtr back)
170942542f5fSchristos{
171042542f5fSchristos	WindowPtr win = (WindowPtr)draw;
171142542f5fSchristos	PixmapPtr pixmap;
171242542f5fSchristos
171342542f5fSchristos	if (!DBG_CAN_XCHG)
171442542f5fSchristos		return false;
171542542f5fSchristos
171642542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
171742542f5fSchristos		return false;
171842542f5fSchristos
171942542f5fSchristos	if (front->format != back->format) {
172042542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
172142542f5fSchristos		     __FUNCTION__, front->format, back->format));
172242542f5fSchristos		return false;
172342542f5fSchristos	}
172442542f5fSchristos
172542542f5fSchristos	pixmap = get_window_pixmap(win);
172642542f5fSchristos	if (get_private(front)->pixmap != pixmap) {
172742542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n",
172842542f5fSchristos		     __FUNCTION__,
172942542f5fSchristos		     get_private(front)->pixmap->drawable.serialNumber,
173042542f5fSchristos		     pixmap->drawable.serialNumber));
173142542f5fSchristos		return false;
173242542f5fSchristos	}
173342542f5fSchristos
173442542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d, pixmap size=%dx%d\n",
173542542f5fSchristos	     __FUNCTION__,
173642542f5fSchristos	     win->drawable.width, win->drawable.height,
173742542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
173842542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
173942542f5fSchristos	     region_num_rects(&win->clipList),
174042542f5fSchristos	     pixmap->drawable.width,
174142542f5fSchristos	     pixmap->drawable.height));
174242542f5fSchristos	if (is_clipped(&win->clipList, &pixmap->drawable)) {
174342542f5fSchristos		DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
174442542f5fSchristos		     __FUNCTION__,
174542542f5fSchristos		     draw->width, draw->height,
174642542f5fSchristos		     win->clipList.extents.x1,
174742542f5fSchristos		     win->clipList.extents.y1,
174842542f5fSchristos		     win->clipList.extents.x2,
174942542f5fSchristos		     win->clipList.extents.y2));
175042542f5fSchristos		return false;
175142542f5fSchristos	}
175242542f5fSchristos
175342542f5fSchristos	if (get_private(back)->size != get_private(front)->size) {
175442542f5fSchristos		DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
175542542f5fSchristos		     __FUNCTION__,
175642542f5fSchristos		     get_private(back)->size & 0x7fff, (get_private(back)->size >> 16) & 0x7fff,
175742542f5fSchristos		     get_private(front)->size & 0x7fff, (get_private(front)->size >> 16) & 0x7fff));
175842542f5fSchristos		return false;
175942542f5fSchristos	}
176042542f5fSchristos
176142542f5fSchristos	if (pixmap == sna->front && !(sna->flags & SNA_TEAR_FREE) && sna->mode.front_active) {
176242542f5fSchristos		DBG(("%s: no, front buffer, requires flipping\n",
176342542f5fSchristos		     __FUNCTION__));
176442542f5fSchristos		return false;
176542542f5fSchristos	}
176642542f5fSchristos
176742542f5fSchristos	if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) {
176842542f5fSchristos		DBG(("%s: no, pinned: %x\n",
176942542f5fSchristos		     __FUNCTION__, sna_pixmap(pixmap)->pinned));
177042542f5fSchristos		return false;
177142542f5fSchristos	}
177242542f5fSchristos
177342542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
177442542f5fSchristos	return true;
177542542f5fSchristos}
177642542f5fSchristos
177742542f5fSchristosstatic bool
177842542f5fSchristosoverlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
177942542f5fSchristos{
178042542f5fSchristos	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
178142542f5fSchristos	int c;
178242542f5fSchristos
178342542f5fSchristos	for (c = 0; c < sna->mode.num_real_crtc; c++) {
178442542f5fSchristos		xf86CrtcPtr crtc = config->crtc[c];
178542542f5fSchristos
178642542f5fSchristos		if (crtc == desired)
178742542f5fSchristos			continue;
178842542f5fSchristos
178942542f5fSchristos		if (!crtc->enabled)
179042542f5fSchristos			continue;
179142542f5fSchristos
179242542f5fSchristos		if (desired->bounds.x1 < crtc->bounds.x2 &&
179342542f5fSchristos		    desired->bounds.x2 > crtc->bounds.x1 &&
179442542f5fSchristos		    desired->bounds.y1 < crtc->bounds.y2 &&
179542542f5fSchristos		    desired->bounds.y2 > crtc->bounds.y1)
179642542f5fSchristos			return true;
179742542f5fSchristos	}
179842542f5fSchristos
179942542f5fSchristos	return false;
180042542f5fSchristos}
180142542f5fSchristos
180242542f5fSchristosstatic bool
180342542f5fSchristoscan_xchg_crtc(struct sna *sna,
180442542f5fSchristos	      DrawablePtr draw,
180542542f5fSchristos	      DRI2BufferPtr front,
180642542f5fSchristos	      DRI2BufferPtr back,
180742542f5fSchristos	      xf86CrtcPtr crtc)
180842542f5fSchristos{
180942542f5fSchristos	WindowPtr win = (WindowPtr)draw;
181042542f5fSchristos	PixmapPtr pixmap;
181142542f5fSchristos
181242542f5fSchristos	if (!DBG_CAN_XCHG)
181342542f5fSchristos		return false;
181442542f5fSchristos
181542542f5fSchristos	if ((sna->flags & SNA_TEAR_FREE) == 0) {
181642542f5fSchristos		DBG(("%s: no, requires TearFree\n",
181742542f5fSchristos		     __FUNCTION__));
181842542f5fSchristos		return false;
181942542f5fSchristos	}
182042542f5fSchristos
182142542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
182242542f5fSchristos		return false;
182342542f5fSchristos
182442542f5fSchristos	if (front->format != back->format) {
182542542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
182642542f5fSchristos		     __FUNCTION__, front->format, back->format));
182742542f5fSchristos		return false;
182842542f5fSchristos	}
182942542f5fSchristos
183042542f5fSchristos	if (memcmp(&win->clipList.extents, &crtc->bounds, sizeof(crtc->bounds))) {
183142542f5fSchristos		DBG(("%s: no, window [(%d, %d), (%d, %d)] does not cover CRTC [(%d, %d), (%d, %d)]\n",
183242542f5fSchristos		     __FUNCTION__,
183342542f5fSchristos		     win->clipList.extents.x1, win->clipList.extents.y1,
183442542f5fSchristos		     win->clipList.extents.x2, win->clipList.extents.y2,
183542542f5fSchristos		     crtc->bounds.x1, crtc->bounds.y1,
183642542f5fSchristos		     crtc->bounds.x2, crtc->bounds.y2));
183742542f5fSchristos		return false;
183842542f5fSchristos	}
183942542f5fSchristos
184042542f5fSchristos	if (sna_crtc_is_transformed(crtc)) {
184142542f5fSchristos		DBG(("%s: no, CRTC is rotated\n", __FUNCTION__));
184242542f5fSchristos		return false;
184342542f5fSchristos	}
184442542f5fSchristos
184542542f5fSchristos	pixmap = get_window_pixmap(win);
184642542f5fSchristos	if (pixmap != sna->front) {
184742542f5fSchristos		DBG(("%s: no, not attached to front buffer\n", __FUNCTION__));
184842542f5fSchristos		return false;
184942542f5fSchristos	}
185042542f5fSchristos
185142542f5fSchristos	if (get_private(front)->pixmap != pixmap) {
185242542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n",
185342542f5fSchristos		     __FUNCTION__,
185442542f5fSchristos		     get_private(front)->pixmap->drawable.serialNumber,
185542542f5fSchristos		     pixmap->drawable.serialNumber));
185642542f5fSchristos		return false;
185742542f5fSchristos	}
185842542f5fSchristos
185942542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
186042542f5fSchristos	     __FUNCTION__,
186142542f5fSchristos	     win->drawable.width, win->drawable.height,
186242542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
186342542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
186442542f5fSchristos	     region_num_rects(&win->clipList)));
186542542f5fSchristos	if (is_clipped(&win->clipList, &win->drawable)) {
186642542f5fSchristos		DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
186742542f5fSchristos		     __FUNCTION__,
186842542f5fSchristos		     draw->width, draw->height,
186942542f5fSchristos		     win->clipList.extents.x1,
187042542f5fSchristos		     win->clipList.extents.y1,
187142542f5fSchristos		     win->clipList.extents.x2,
187242542f5fSchristos		     win->clipList.extents.y2));
187342542f5fSchristos		return false;
187442542f5fSchristos	}
187542542f5fSchristos
187642542f5fSchristos	if (overlaps_other_crtc(sna, crtc)) {
187742542f5fSchristos		DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__));
187842542f5fSchristos		return false;
187942542f5fSchristos	}
188042542f5fSchristos
188142542f5fSchristos	if (get_private(back)->size != (draw->height << 16 | draw->width)) {
188242542f5fSchristos		DBG(("%s: no, DRI2 buffers does not fit window\n",
188342542f5fSchristos		     __FUNCTION__));
188442542f5fSchristos		return false;
188542542f5fSchristos	}
188642542f5fSchristos
188742542f5fSchristos	assert(win != win->drawable.pScreen->root);
188842542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
188942542f5fSchristos	return true;
189042542f5fSchristos}
189142542f5fSchristos
189242542f5fSchristosstatic void
189342542f5fSchristossna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
189442542f5fSchristos{
189542542f5fSchristos	WindowPtr win = (WindowPtr)draw;
189642542f5fSchristos	struct kgem_bo *back_bo, *front_bo;
189742542f5fSchristos	PixmapPtr pixmap;
189842542f5fSchristos	int tmp;
189942542f5fSchristos
190042542f5fSchristos	assert(draw->type != DRAWABLE_PIXMAP);
190142542f5fSchristos	pixmap = get_window_pixmap(win);
190242542f5fSchristos
190342542f5fSchristos	back_bo = get_private(back)->bo;
190442542f5fSchristos	front_bo = get_private(front)->bo;
190542542f5fSchristos	assert(front_bo != back_bo);
190642542f5fSchristos
190742542f5fSchristos	DBG(("%s: win=%ld, exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n",
190842542f5fSchristos	     __FUNCTION__, win->drawable.id,
190942542f5fSchristos	     front_bo->handle, front->name,
191042542f5fSchristos	     back_bo->handle, back->name,
191142542f5fSchristos	     pixmap->drawable.serialNumber,
191242542f5fSchristos	     pixmap->drawable.width,
191342542f5fSchristos	     pixmap->drawable.height));
191442542f5fSchristos
191542542f5fSchristos	DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
191642542f5fSchristos	     __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
191742542f5fSchristos	DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
191842542f5fSchristos	     __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
191942542f5fSchristos	assert(front_bo->refcnt);
192042542f5fSchristos	assert(back_bo->refcnt);
192142542f5fSchristos
192242542f5fSchristos	assert(sna_pixmap_get_buffer(pixmap) == front);
192342542f5fSchristos
192442542f5fSchristos	assert(pixmap->drawable.height * back_bo->pitch <= kgem_bo_size(back_bo));
192542542f5fSchristos	assert(pixmap->drawable.height * front_bo->pitch <= kgem_bo_size(front_bo));
192642542f5fSchristos
192742542f5fSchristos	set_bo(pixmap, back_bo);
192842542f5fSchristos
192942542f5fSchristos	get_private(front)->bo = back_bo;
193042542f5fSchristos	get_private(back)->bo = front_bo;
193142542f5fSchristos	get_private(back)->stale = true;
193242542f5fSchristos
193342542f5fSchristos	tmp = front->name;
193442542f5fSchristos	front->name = back->name;
193542542f5fSchristos	back->name = tmp;
193642542f5fSchristos
193742542f5fSchristos	assert(front_bo->refcnt);
193842542f5fSchristos	assert(back_bo->refcnt);
193942542f5fSchristos
194042542f5fSchristos	assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
194142542f5fSchristos}
194242542f5fSchristos
194342542f5fSchristosstatic void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back)
194442542f5fSchristos{
194542542f5fSchristos	WindowPtr win = (WindowPtr)draw;
194642542f5fSchristos	DRI2Buffer2Ptr tmp;
194742542f5fSchristos	struct kgem_bo *bo;
194842542f5fSchristos
194942542f5fSchristos	DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n",
195042542f5fSchristos	     __FUNCTION__,
195142542f5fSchristos	     get_private(front)->bo->handle, front->name,
195242542f5fSchristos	     get_private(back)->bo->handle, back->name,
195342542f5fSchristos	     win->drawable.id,
195442542f5fSchristos	     get_window_pixmap(win)->drawable.serialNumber,
195542542f5fSchristos	     get_window_pixmap(win)->drawable.width,
195642542f5fSchristos	     get_window_pixmap(win)->drawable.height));
195742542f5fSchristos
195842542f5fSchristos	DamageRegionAppend(&win->drawable, &win->clipList);
195942542f5fSchristos	sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
196042542f5fSchristos	DamageRegionProcessPending(&win->drawable);
196142542f5fSchristos
196242542f5fSchristos	assert(dri2_window(win)->front == NULL);
196342542f5fSchristos
196442542f5fSchristos	tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
196542542f5fSchristos	if (tmp == NULL) {
196642542f5fSchristos		back->attachment = -1;
196742542f5fSchristos		if (get_private(back)->proxy == NULL) {
196842542f5fSchristos			get_private(back)->pixmap = get_window_pixmap(win);
196942542f5fSchristos			get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap));
197042542f5fSchristos		}
197142542f5fSchristos		dri2_window(win)->front = sna_dri2_reference_buffer(back);
197242542f5fSchristos		return;
197342542f5fSchristos	}
197442542f5fSchristos
197542542f5fSchristos	*tmp = *back;
197642542f5fSchristos	tmp->attachment = DRI2BufferFrontLeft;
197742542f5fSchristos	tmp->driverPrivate = tmp + 1;
197842542f5fSchristos	get_private(tmp)->refcnt = 1;
197942542f5fSchristos	get_private(tmp)->bo = get_private(back)->bo;
198042542f5fSchristos	get_private(tmp)->size = get_private(back)->size;
198142542f5fSchristos	get_private(tmp)->pixmap = get_window_pixmap(win);
198242542f5fSchristos	get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap));
198342542f5fSchristos	dri2_window(win)->front = tmp;
198442542f5fSchristos
198542542f5fSchristos	DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
198642542f5fSchristos	back->name = 0;
198742542f5fSchristos	bo = kgem_create_2d(&sna->kgem,
198842542f5fSchristos			    draw->width, draw->height, draw->bitsPerPixel,
198942542f5fSchristos			    get_private(back)->bo->tiling,
199042542f5fSchristos			    CREATE_SCANOUT);
199142542f5fSchristos	if (bo != NULL) {
199242542f5fSchristos		get_private(back)->bo = bo;
199342542f5fSchristos		back->pitch = bo->pitch;
199442542f5fSchristos		back->name = kgem_bo_flink(&sna->kgem, bo);
199542542f5fSchristos	}
199642542f5fSchristos	if (back->name == 0) {
199742542f5fSchristos		if (bo != NULL)
199842542f5fSchristos			kgem_bo_destroy(&sna->kgem, bo);
199942542f5fSchristos		get_private(back)->bo = NULL;
200042542f5fSchristos		back->attachment = -1;
200142542f5fSchristos	}
200242542f5fSchristos}
200342542f5fSchristos
200442542f5fSchristosstatic void frame_swap_complete(struct sna *sna,
200542542f5fSchristos				struct sna_dri2_event *frame,
200642542f5fSchristos				int type)
200742542f5fSchristos{
200842542f5fSchristos	const struct ust_msc *swap;
200942542f5fSchristos
201042542f5fSchristos	if (frame->draw == NULL)
201142542f5fSchristos		return;
201242542f5fSchristos
201342542f5fSchristos	assert(frame->client);
201442542f5fSchristos
201542542f5fSchristos	swap = sna_crtc_last_swap(frame->crtc);
201642542f5fSchristos	DBG(("%s: draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
201742542f5fSchristos	     __FUNCTION__, (long)frame->draw, frame->pipe,
201842542f5fSchristos	     (long long)swap->msc,
201942542f5fSchristos	     (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
202042542f5fSchristos	     swap->tv_sec, swap->tv_usec));
202142542f5fSchristos
202242542f5fSchristos	DRI2SwapComplete(frame->client, frame->draw,
202342542f5fSchristos			 draw_current_msc(frame->draw, frame->crtc, swap->msc),
202442542f5fSchristos			 swap->tv_sec, swap->tv_usec,
202542542f5fSchristos			 type, frame->event_complete, frame->event_data);
202642542f5fSchristos}
202742542f5fSchristos
202842542f5fSchristosstatic void fake_swap_complete(struct sna *sna, ClientPtr client,
202942542f5fSchristos			       DrawablePtr draw, xf86CrtcPtr crtc,
203042542f5fSchristos			       int type, DRI2SwapEventPtr func, void *data)
203142542f5fSchristos{
203242542f5fSchristos	const struct ust_msc *swap;
203342542f5fSchristos
203442542f5fSchristos	swap = sna_crtc_last_swap(crtc);
203542542f5fSchristos	DBG(("%s: draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
203642542f5fSchristos	     __FUNCTION__, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
203742542f5fSchristos	     (long long)swap->msc,
203842542f5fSchristos	     (long long)draw_current_msc(draw, crtc, swap->msc),
203942542f5fSchristos	     swap->tv_sec, swap->tv_usec));
204042542f5fSchristos
204142542f5fSchristos	DRI2SwapComplete(client, draw,
204242542f5fSchristos			 draw_current_msc(draw, crtc, swap->msc),
204342542f5fSchristos			 swap->tv_sec, swap->tv_usec,
204442542f5fSchristos			 type, func, data);
204542542f5fSchristos}
204642542f5fSchristos
204742542f5fSchristosstatic void chain_swap(struct sna *sna, struct sna_dri2_event *chain)
204842542f5fSchristos{
204942542f5fSchristos	union drm_wait_vblank vbl;
205042542f5fSchristos
205142542f5fSchristos	if (chain->draw == NULL) {
205242542f5fSchristos		sna_dri2_event_free(sna, chain);
205342542f5fSchristos		return;
205442542f5fSchristos	}
205542542f5fSchristos
205642542f5fSchristos	if (chain->queued) /* too early! */
205742542f5fSchristos		return;
205842542f5fSchristos
205942542f5fSchristos	assert(chain == dri2_chain(chain->draw));
206042542f5fSchristos	DBG(("%s: chaining draw=%ld, type=%d\n",
206142542f5fSchristos	     __FUNCTION__, (long)chain->draw->id, chain->type));
206242542f5fSchristos	chain->queued = true;
206342542f5fSchristos
206442542f5fSchristos	switch (chain->type) {
206542542f5fSchristos	case SWAP_THROTTLE:
206642542f5fSchristos		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
206742542f5fSchristos		if (sna->mode.shadow && !sna->mode.shadow_damage) {
206842542f5fSchristos			/* recursed from wait_for_shadow(), simply requeue */
206942542f5fSchristos			DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
207042542f5fSchristos			VG_CLEAR(vbl);
207142542f5fSchristos			vbl.request.type =
207242542f5fSchristos				DRM_VBLANK_RELATIVE |
207342542f5fSchristos				DRM_VBLANK_EVENT;
207442542f5fSchristos			vbl.request.sequence = 1;
207542542f5fSchristos			vbl.request.signal = (uintptr_t)chain;
207642542f5fSchristos
207742542f5fSchristos			if (!sna_wait_vblank(sna, &vbl, chain->pipe))
207842542f5fSchristos				return;
207942542f5fSchristos
208042542f5fSchristos			DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
208142542f5fSchristos		}
208242542f5fSchristos
208342542f5fSchristos		if (can_xchg(sna, chain->draw, chain->front, chain->back)) {
208442542f5fSchristos			sna_dri2_xchg(chain->draw, chain->front, chain->back);
208542542f5fSchristos		} else if (can_xchg_crtc(sna, chain->draw, chain->front, chain->back, chain->crtc)) {
208642542f5fSchristos			sna_dri2_xchg_crtc(sna, chain->draw, chain->crtc, chain->front, chain->back);
208742542f5fSchristos		} else {
208842542f5fSchristos			assert(chain->queued);
208942542f5fSchristos			chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
209042542f5fSchristos							   chain->back, chain->front,
209142542f5fSchristos							   true);
209242542f5fSchristos		}
209342542f5fSchristos	case SWAP:
209442542f5fSchristos		break;
209542542f5fSchristos	default:
209642542f5fSchristos		return;
209742542f5fSchristos	}
209842542f5fSchristos
209942542f5fSchristos	VG_CLEAR(vbl);
210042542f5fSchristos	vbl.request.type =
210142542f5fSchristos		DRM_VBLANK_RELATIVE |
210242542f5fSchristos		DRM_VBLANK_EVENT;
210342542f5fSchristos	vbl.request.sequence = 1;
210442542f5fSchristos	vbl.request.signal = (uintptr_t)chain;
210542542f5fSchristos	if (sna_wait_vblank(sna, &vbl, chain->pipe)) {
210642542f5fSchristos		DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
210742542f5fSchristos		frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
210842542f5fSchristos		sna_dri2_event_free(sna, chain);
210942542f5fSchristos	} else {
211042542f5fSchristos		if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) {
211142542f5fSchristos			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
211242542f5fSchristos			frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
211342542f5fSchristos		}
211442542f5fSchristos	}
211542542f5fSchristos}
211642542f5fSchristos
211742542f5fSchristosstatic inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
211842542f5fSchristos{
211942542f5fSchristos	if (bo == NULL)
212042542f5fSchristos		return false;
212142542f5fSchristos
212242542f5fSchristos	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
212342542f5fSchristos	     bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL));
212442542f5fSchristos	assert(bo->refcnt);
212542542f5fSchristos
212642542f5fSchristos	if (bo->exec)
212742542f5fSchristos		return true;
212842542f5fSchristos
212942542f5fSchristos	if (bo->rq == NULL)
213042542f5fSchristos		return false;
213142542f5fSchristos
213242542f5fSchristos	return __kgem_busy(kgem, bo->handle);
213342542f5fSchristos}
213442542f5fSchristos
213542542f5fSchristosstatic bool sna_dri2_blit_complete(struct sna *sna,
213642542f5fSchristos				   struct sna_dri2_event *info)
213742542f5fSchristos{
213842542f5fSchristos	if (rq_is_busy(&sna->kgem, info->bo)) {
213942542f5fSchristos		union drm_wait_vblank vbl;
214042542f5fSchristos
214142542f5fSchristos		DBG(("%s: vsync'ed blit is still busy, postponing\n",
214242542f5fSchristos		     __FUNCTION__));
214342542f5fSchristos
214442542f5fSchristos		VG_CLEAR(vbl);
214542542f5fSchristos		vbl.request.type =
214642542f5fSchristos			DRM_VBLANK_RELATIVE |
214742542f5fSchristos			DRM_VBLANK_EVENT;
214842542f5fSchristos		vbl.request.sequence = 1;
214942542f5fSchristos		vbl.request.signal = (uintptr_t)info;
215042542f5fSchristos		assert(info->queued);
215142542f5fSchristos		if (!sna_wait_vblank(sna, &vbl, info->pipe))
215242542f5fSchristos			return false;
215342542f5fSchristos	}
215442542f5fSchristos
215542542f5fSchristos	DBG(("%s: blit finished\n", __FUNCTION__));
215642542f5fSchristos	return true;
215742542f5fSchristos}
215842542f5fSchristos
215942542f5fSchristosvoid sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
216042542f5fSchristos{
216142542f5fSchristos	struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
216242542f5fSchristos	DrawablePtr draw;
216342542f5fSchristos	union drm_wait_vblank vbl;
216442542f5fSchristos	uint64_t msc;
216542542f5fSchristos
216642542f5fSchristos	DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence));
216742542f5fSchristos	assert(info->queued);
216842542f5fSchristos	msc = sna_crtc_record_event(info->crtc, event);
216942542f5fSchristos
217042542f5fSchristos	draw = info->draw;
217142542f5fSchristos	if (draw == NULL) {
217242542f5fSchristos		DBG(("%s -- drawable gone\n", __FUNCTION__));
217342542f5fSchristos		goto done;
217442542f5fSchristos	}
217542542f5fSchristos
217642542f5fSchristos	switch (info->type) {
217742542f5fSchristos	case FLIP:
217842542f5fSchristos		/* If we can still flip... */
217942542f5fSchristos		if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
218042542f5fSchristos		    sna_dri2_flip(sna, info))
218142542f5fSchristos			return;
218242542f5fSchristos
218342542f5fSchristos		/* else fall through to blit */
218442542f5fSchristos	case SWAP:
218542542f5fSchristos		assert(info->queued);
218642542f5fSchristos		if (sna->mode.shadow && !sna->mode.shadow_damage) {
218742542f5fSchristos			/* recursed from wait_for_shadow(), simply requeue */
218842542f5fSchristos			DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
218942542f5fSchristos
219042542f5fSchristos		} else if (can_xchg(sna, draw, info->front, info->back)) {
219142542f5fSchristos			sna_dri2_xchg(draw, info->front, info->back);
219242542f5fSchristos			info->type = SWAP_WAIT;
219342542f5fSchristos		} else if (can_xchg_crtc(sna, draw, info->front, info->back, info->crtc)) {
219442542f5fSchristos			sna_dri2_xchg_crtc(sna, draw, info->crtc, info->front, info->back);
219542542f5fSchristos			info->type = SWAP_WAIT;
219642542f5fSchristos		}  else {
219742542f5fSchristos			assert(info->queued);
219842542f5fSchristos			info->bo = __sna_dri2_copy_region(sna, draw, NULL,
219942542f5fSchristos							  info->back, info->front, true);
220042542f5fSchristos			info->type = SWAP_WAIT;
220142542f5fSchristos		}
220242542f5fSchristos
220342542f5fSchristos		VG_CLEAR(vbl);
220442542f5fSchristos		vbl.request.type =
220542542f5fSchristos			DRM_VBLANK_RELATIVE |
220642542f5fSchristos			DRM_VBLANK_EVENT;
220742542f5fSchristos		vbl.request.sequence = 1;
220842542f5fSchristos		vbl.request.signal = (uintptr_t)info;
220942542f5fSchristos
221042542f5fSchristos		assert(info->queued);
221142542f5fSchristos		if (!sna_wait_vblank(sna, &vbl, info->pipe))
221242542f5fSchristos			return;
221342542f5fSchristos
221442542f5fSchristos		DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
221542542f5fSchristos		/* fall through to SwapComplete */
221642542f5fSchristos	case SWAP_WAIT:
221742542f5fSchristos		if (!sna_dri2_blit_complete(sna, info))
221842542f5fSchristos			return;
221942542f5fSchristos
222042542f5fSchristos		DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
222142542f5fSchristos		     event->sequence, event->tv_sec, event->tv_usec));
222242542f5fSchristos		frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
222342542f5fSchristos		break;
222442542f5fSchristos
222542542f5fSchristos	case SWAP_THROTTLE:
222642542f5fSchristos		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
222742542f5fSchristos		     __FUNCTION__, info->type,
222842542f5fSchristos		     event->sequence, event->tv_sec, event->tv_usec));
222942542f5fSchristos
223042542f5fSchristos		if (xorg_can_triple_buffer(sna)) {
223142542f5fSchristos			if (!sna_dri2_blit_complete(sna, info))
223242542f5fSchristos				return;
223342542f5fSchristos
223442542f5fSchristos			DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
223542542f5fSchristos			     event->sequence, event->tv_sec, event->tv_usec));
223642542f5fSchristos			frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
223742542f5fSchristos		}
223842542f5fSchristos		break;
223942542f5fSchristos
224042542f5fSchristos	case WAITMSC:
224142542f5fSchristos		assert(info->client);
224242542f5fSchristos		DRI2WaitMSCComplete(info->client, draw, msc,
224342542f5fSchristos				    event->tv_sec, event->tv_usec);
224442542f5fSchristos		break;
224542542f5fSchristos	default:
224642542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
224742542f5fSchristos			   "%s: unknown vblank event received\n", __func__);
224842542f5fSchristos		/* Unknown type */
224942542f5fSchristos		break;
225042542f5fSchristos	}
225142542f5fSchristos
225242542f5fSchristos	if (info->chain) {
225342542f5fSchristos		assert(info->chain != info);
225442542f5fSchristos		assert(info->draw == draw);
225542542f5fSchristos		sna_dri2_remove_event((WindowPtr)draw, info);
225642542f5fSchristos		chain_swap(sna, info->chain);
225742542f5fSchristos		info->draw = NULL;
225842542f5fSchristos	}
225942542f5fSchristos
226042542f5fSchristosdone:
226142542f5fSchristos	sna_dri2_event_free(sna, info);
226242542f5fSchristos	DBG(("%s complete\n", __FUNCTION__));
226342542f5fSchristos}
226442542f5fSchristos
226542542f5fSchristosstatic bool
226642542f5fSchristossna_dri2_immediate_blit(struct sna *sna,
226742542f5fSchristos			struct sna_dri2_event *info,
226842542f5fSchristos			bool sync, bool event)
226942542f5fSchristos{
227042542f5fSchristos	DrawablePtr draw = info->draw;
227142542f5fSchristos	bool ret = false;
227242542f5fSchristos
227342542f5fSchristos	if (sna->flags & SNA_NO_WAIT)
227442542f5fSchristos		sync = false;
227542542f5fSchristos
227642542f5fSchristos	DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, send-event? %d\n",
227742542f5fSchristos	     __FUNCTION__, sync, dri2_chain(draw) != info,
227842542f5fSchristos	     event));
227942542f5fSchristos
228042542f5fSchristos	info->type = SWAP_THROTTLE;
228142542f5fSchristos	if (!sync || dri2_chain(draw) == info) {
228242542f5fSchristos		DBG(("%s: no pending blit, starting chain\n",
228342542f5fSchristos		     __FUNCTION__));
228442542f5fSchristos
228542542f5fSchristos		info->queued = true;
228642542f5fSchristos		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
228742542f5fSchristos						  info->back,
228842542f5fSchristos						  info->front,
228942542f5fSchristos						  sync);
229042542f5fSchristos		if (event) {
229142542f5fSchristos			if (sync) {
229242542f5fSchristos				union drm_wait_vblank vbl;
229342542f5fSchristos
229442542f5fSchristos				VG_CLEAR(vbl);
229542542f5fSchristos				vbl.request.type =
229642542f5fSchristos					DRM_VBLANK_RELATIVE |
229742542f5fSchristos					DRM_VBLANK_EVENT;
229842542f5fSchristos				vbl.request.sequence = 1;
229942542f5fSchristos				vbl.request.signal = (uintptr_t)info;
230042542f5fSchristos				ret = !sna_wait_vblank(sna, &vbl, info->pipe);
230142542f5fSchristos				if (ret)
230242542f5fSchristos					event = !swap_limit(draw, 2);
230342542f5fSchristos			}
230442542f5fSchristos			if (event) {
230542542f5fSchristos				DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
230642542f5fSchristos				frame_swap_complete(sna, info, DRI2_BLIT_COMPLETE);
230742542f5fSchristos			}
230842542f5fSchristos		}
230942542f5fSchristos	} else {
231042542f5fSchristos		DBG(("%s: pending blit, chained\n", __FUNCTION__));
231142542f5fSchristos		ret = true;
231242542f5fSchristos	}
231342542f5fSchristos
231442542f5fSchristos	DBG(("%s: continue? %d\n", __FUNCTION__, ret));
231542542f5fSchristos	return ret;
231642542f5fSchristos}
231742542f5fSchristos
231842542f5fSchristosstatic bool
231942542f5fSchristossna_dri2_flip_continue(struct sna *sna, struct sna_dri2_event *info)
232042542f5fSchristos{
232142542f5fSchristos	DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
232242542f5fSchristos
232342542f5fSchristos	if (info->mode > 0){
232442542f5fSchristos		struct kgem_bo *bo = get_private(info->front)->bo;
232542542f5fSchristos
232642542f5fSchristos		info->type = info->mode;
232742542f5fSchristos
232842542f5fSchristos		if (bo != sna_pixmap(sna->front)->gpu_bo)
232942542f5fSchristos			return false;
233042542f5fSchristos
233142542f5fSchristos		if (!sna_page_flip(sna, bo, sna_dri2_flip_handler, info))
233242542f5fSchristos			return false;
233342542f5fSchristos
233442542f5fSchristos		assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
233542542f5fSchristos		sna->dri2.flip_pending = info;
233642542f5fSchristos		assert(info->queued);
233742542f5fSchristos	} else {
233842542f5fSchristos		info->type = -info->mode;
233942542f5fSchristos
234042542f5fSchristos		if (!info->draw)
234142542f5fSchristos			return false;
234242542f5fSchristos
234342542f5fSchristos		if (!can_flip(sna, info->draw, info->front, info->back, info->crtc))
234442542f5fSchristos			return false;
234542542f5fSchristos
234642542f5fSchristos		assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
234742542f5fSchristos		if (!sna_dri2_flip(sna, info))
234842542f5fSchristos			return false;
234942542f5fSchristos
235042542f5fSchristos		if (!xorg_can_triple_buffer(sna)) {
235142542f5fSchristos			sna_dri2_get_back(sna, info->draw, info->back, info);
235242542f5fSchristos			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
235342542f5fSchristos			frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
235442542f5fSchristos		}
235542542f5fSchristos	}
235642542f5fSchristos
235742542f5fSchristos	info->mode = 0;
235842542f5fSchristos	return true;
235942542f5fSchristos}
236042542f5fSchristos
236142542f5fSchristosstatic void chain_flip(struct sna *sna)
236242542f5fSchristos{
236342542f5fSchristos	struct sna_dri2_event *chain = sna->dri2.flip_pending;
236442542f5fSchristos
236542542f5fSchristos	assert(chain->type == FLIP);
236642542f5fSchristos	DBG(("%s: chaining type=%d, cancelled?=%d\n",
236742542f5fSchristos	     __FUNCTION__, chain->type, chain->draw == NULL));
236842542f5fSchristos
236942542f5fSchristos	sna->dri2.flip_pending = NULL;
237042542f5fSchristos	if (chain->draw == NULL) {
237142542f5fSchristos		sna_dri2_event_free(sna, chain);
237242542f5fSchristos		return;
237342542f5fSchristos	}
237442542f5fSchristos
237542542f5fSchristos	assert(chain == dri2_chain(chain->draw));
237642542f5fSchristos	assert(!chain->queued);
237742542f5fSchristos	chain->queued = true;
237842542f5fSchristos
237942542f5fSchristos	if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
238042542f5fSchristos	    sna_dri2_flip(sna, chain)) {
238142542f5fSchristos		DBG(("%s: performing chained flip\n", __FUNCTION__));
238242542f5fSchristos	} else {
238342542f5fSchristos		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
238442542f5fSchristos		chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
238542542f5fSchristos						  chain->back, chain->front,
238642542f5fSchristos						  true);
238742542f5fSchristos
238842542f5fSchristos		if (xorg_can_triple_buffer(sna)) {
238942542f5fSchristos			union drm_wait_vblank vbl;
239042542f5fSchristos
239142542f5fSchristos			VG_CLEAR(vbl);
239242542f5fSchristos
239342542f5fSchristos			chain->type = SWAP_WAIT;
239442542f5fSchristos			vbl.request.type =
239542542f5fSchristos				DRM_VBLANK_RELATIVE |
239642542f5fSchristos				DRM_VBLANK_EVENT;
239742542f5fSchristos			vbl.request.sequence = 1;
239842542f5fSchristos			vbl.request.signal = (uintptr_t)chain;
239942542f5fSchristos
240042542f5fSchristos			assert(chain->queued);
240142542f5fSchristos			if (!sna_wait_vblank(sna, &vbl, chain->pipe))
240242542f5fSchristos				return;
240342542f5fSchristos		}
240442542f5fSchristos
240542542f5fSchristos		DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__));
240642542f5fSchristos		frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
240742542f5fSchristos		sna_dri2_event_free(sna, chain);
240842542f5fSchristos	}
240942542f5fSchristos}
241042542f5fSchristos
241142542f5fSchristosstatic void sna_dri2_flip_event(struct sna *sna,
241242542f5fSchristos				struct sna_dri2_event *flip)
241342542f5fSchristos{
241442542f5fSchristos	DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type));
241542542f5fSchristos	assert(flip->queued);
241642542f5fSchristos
241742542f5fSchristos	if (sna->dri2.flip_pending == flip)
241842542f5fSchristos		sna->dri2.flip_pending = NULL;
241942542f5fSchristos
242042542f5fSchristos	/* We assume our flips arrive in order, so we don't check the frame */
242142542f5fSchristos	switch (flip->type) {
242242542f5fSchristos	case FLIP:
242342542f5fSchristos		DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
242442542f5fSchristos		frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
242542542f5fSchristos		sna_dri2_event_free(sna, flip);
242642542f5fSchristos
242742542f5fSchristos		if (sna->dri2.flip_pending)
242842542f5fSchristos			chain_flip(sna);
242942542f5fSchristos		break;
243042542f5fSchristos
243142542f5fSchristos	case FLIP_THROTTLE:
243242542f5fSchristos		DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
243342542f5fSchristos		frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
243442542f5fSchristos	case FLIP_COMPLETE:
243542542f5fSchristos		if (sna->dri2.flip_pending) {
243642542f5fSchristos			sna_dri2_event_free(sna, flip);
243742542f5fSchristos			chain_flip(sna);
243842542f5fSchristos		} else if (!flip->mode) {
243942542f5fSchristos			DBG(("%s: flip chain complete\n", __FUNCTION__));
244042542f5fSchristos
244142542f5fSchristos			if (flip->chain) {
244242542f5fSchristos				sna_dri2_remove_event((WindowPtr)flip->draw,
244342542f5fSchristos						      flip);
244442542f5fSchristos				chain_swap(sna, flip->chain);
244542542f5fSchristos				flip->draw = NULL;
244642542f5fSchristos			}
244742542f5fSchristos
244842542f5fSchristos			sna_dri2_event_free(sna, flip);
244942542f5fSchristos		} else if (!sna_dri2_flip_continue(sna, flip)) {
245042542f5fSchristos			DBG(("%s: no longer able to flip\n", __FUNCTION__));
245142542f5fSchristos			if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
245242542f5fSchristos				sna_dri2_event_free(sna, flip);
245342542f5fSchristos		}
245442542f5fSchristos		break;
245542542f5fSchristos
245642542f5fSchristos	default: /* Unknown type */
245742542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
245842542f5fSchristos			   "%s: unknown vblank event received\n", __func__);
245942542f5fSchristos		sna_dri2_event_free(sna, flip);
246042542f5fSchristos		if (sna->dri2.flip_pending)
246142542f5fSchristos			chain_flip(sna);
246242542f5fSchristos		break;
246342542f5fSchristos	}
246442542f5fSchristos}
246542542f5fSchristos
246642542f5fSchristosstatic uint64_t
246742542f5fSchristosget_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
246842542f5fSchristos{
246942542f5fSchristos	union drm_wait_vblank vbl;
247042542f5fSchristos	uint64_t ret = -1;
247142542f5fSchristos
247242542f5fSchristos	VG_CLEAR(vbl);
247342542f5fSchristos	vbl.request.type = _DRM_VBLANK_RELATIVE;
247442542f5fSchristos	vbl.request.sequence = 0;
247542542f5fSchristos	if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
247642542f5fSchristos		ret = sna_crtc_record_vblank(crtc, &vbl);
247742542f5fSchristos
247842542f5fSchristos	return draw_current_msc(draw, crtc, ret);
247942542f5fSchristos}
248042542f5fSchristos
248142542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR)
248242542f5fSchristosstatic Bool find(pointer value, XID id, pointer cdata)
248342542f5fSchristos{
248442542f5fSchristos	return TRUE;
248542542f5fSchristos}
248642542f5fSchristos#endif
248742542f5fSchristos
248842542f5fSchristosstatic int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
248942542f5fSchristos{
249042542f5fSchristos	if ((sna->flags & SNA_TRIPLE_BUFFER) == 0) {
249142542f5fSchristos		DBG(("%s: triple buffer disabled, using FLIP\n", __FUNCTION__));
249242542f5fSchristos		return FLIP;
249342542f5fSchristos	}
249442542f5fSchristos
249542542f5fSchristos	if (async) {
249642542f5fSchristos		DBG(("%s: running async, using %s\n", __FUNCTION__,
249742542f5fSchristos		     sna->flags & SNA_HAS_ASYNC_FLIP ? "FLIP_ASYNC" : "FLIP_COMPLETE"));
249842542f5fSchristos		return sna->flags & SNA_HAS_ASYNC_FLIP ? FLIP_ASYNC : FLIP_COMPLETE;
249942542f5fSchristos	}
250042542f5fSchristos
250142542f5fSchristos	if (xorg_can_triple_buffer(sna)) {
250242542f5fSchristos		DBG(("%s: triple buffer enabled, using FLIP_THROTTLE\n", __FUNCTION__));
250342542f5fSchristos		return FLIP_THROTTLE;
250442542f5fSchristos	}
250542542f5fSchristos
250642542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR)
250742542f5fSchristos	/* Hack: Disable triple buffering for compositors */
250842542f5fSchristos	{
250942542f5fSchristos		struct sna_client *priv = sna_client(client);
251042542f5fSchristos		if (priv->is_compositor == 0)
251142542f5fSchristos			priv->is_compositor =
251242542f5fSchristos				LookupClientResourceComplex(client,
251342542f5fSchristos							    CompositeClientWindowType+1,
251442542f5fSchristos							    find, NULL) ? FLIP : FLIP_COMPLETE;
251542542f5fSchristos
251642542f5fSchristos		DBG(("%s: fake triple buffer enabled?=%d using %s\n", __FUNCTION__,
251742542f5fSchristos		     priv->is_compositor != FLIP, priv->is_compositor == FLIP ? "FLIP" : "FLIP_COMPLETE"));
251842542f5fSchristos		return priv->is_compositor;
251942542f5fSchristos	}
252042542f5fSchristos#else
252142542f5fSchristos	DBG(("%s: fake triple buffer enabled, using FLIP_COMPLETE\n", __FUNCTION__));
252242542f5fSchristos	return FLIP_COMPLETE;
252342542f5fSchristos#endif
252442542f5fSchristos}
252542542f5fSchristos
252642542f5fSchristosstatic bool immediate_swap(struct sna *sna,
252742542f5fSchristos			   uint64_t target_msc,
252842542f5fSchristos			   uint64_t divisor,
252942542f5fSchristos			   DrawablePtr draw,
253042542f5fSchristos			   xf86CrtcPtr crtc,
253142542f5fSchristos			   uint64_t *current_msc)
253242542f5fSchristos{
253342542f5fSchristos	if (divisor == 0) {
253442542f5fSchristos		*current_msc = -1;
253542542f5fSchristos
253642542f5fSchristos		if (sna->flags & SNA_NO_WAIT) {
253742542f5fSchristos			DBG(("%s: yes, waits are disabled\n", __FUNCTION__));
253842542f5fSchristos			return true;
253942542f5fSchristos		}
254042542f5fSchristos
254142542f5fSchristos		if (target_msc)
254242542f5fSchristos			*current_msc = get_current_msc(sna, draw, crtc);
254342542f5fSchristos
254442542f5fSchristos		DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
254542542f5fSchristos		     __FUNCTION__, (long)*current_msc, (long)target_msc,
254642542f5fSchristos		     (*current_msc >= target_msc - 1) ? "yes" : "no"));
254742542f5fSchristos		return *current_msc >= target_msc - 1;
254842542f5fSchristos	}
254942542f5fSchristos
255042542f5fSchristos	DBG(("%s: explicit waits requests, divisor=%ld\n",
255142542f5fSchristos	     __FUNCTION__, (long)divisor));
255242542f5fSchristos	*current_msc = get_current_msc(sna, draw, crtc);
255342542f5fSchristos	return false;
255442542f5fSchristos}
255542542f5fSchristos
255642542f5fSchristosstatic bool
255742542f5fSchristossna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
255842542f5fSchristos		       DRI2BufferPtr front, DRI2BufferPtr back,
255942542f5fSchristos		       CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
256042542f5fSchristos		       DRI2SwapEventPtr func, void *data)
256142542f5fSchristos{
256242542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
256342542f5fSchristos	struct sna_dri2_event *info;
256442542f5fSchristos	uint64_t current_msc;
256542542f5fSchristos
256642542f5fSchristos	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
256742542f5fSchristos		int type;
256842542f5fSchristos
256942542f5fSchristos		info = sna->dri2.flip_pending;
257042542f5fSchristos		DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
257142542f5fSchristos		     __FUNCTION__, sna_crtc_to_pipe(crtc),
257242542f5fSchristos		     info != NULL, info ? info->mode : 0,
257342542f5fSchristos		     info && info->draw == draw));
257442542f5fSchristos
257542542f5fSchristos		if (info && info->draw == draw) {
257642542f5fSchristos			assert(info->type != FLIP);
257742542f5fSchristos			assert(info->front == front);
257842542f5fSchristos			if (info->back != back) {
257942542f5fSchristos				_sna_dri2_destroy_buffer(sna, info->back);
258042542f5fSchristos				info->back = sna_dri2_reference_buffer(back);
258142542f5fSchristos			}
258242542f5fSchristos			if (info->mode || current_msc >= *target_msc) {
258342542f5fSchristos				DBG(("%s: executing xchg of pending flip\n",
258442542f5fSchristos				     __FUNCTION__));
258542542f5fSchristos				sna_dri2_xchg(draw, front, back);
258642542f5fSchristos				info->mode = type = FLIP_COMPLETE;
258742542f5fSchristos				goto new_back;
258842542f5fSchristos			} else {
258942542f5fSchristos				DBG(("%s: chaining flip\n", __FUNCTION__));
259042542f5fSchristos				type = FLIP_THROTTLE;
259142542f5fSchristos				if (xorg_can_triple_buffer(sna))
259242542f5fSchristos					info->mode = -type;
259342542f5fSchristos				else
259442542f5fSchristos					info->mode = -FLIP_COMPLETE;
259542542f5fSchristos				goto out;
259642542f5fSchristos			}
259742542f5fSchristos		}
259842542f5fSchristos
259942542f5fSchristos		info = sna_dri2_add_event(sna, draw, client);
260042542f5fSchristos		if (info == NULL)
260142542f5fSchristos			return false;
260242542f5fSchristos
260342542f5fSchristos		assert(info->crtc == crtc);
260442542f5fSchristos		info->event_complete = func;
260542542f5fSchristos		info->event_data = data;
260642542f5fSchristos
260742542f5fSchristos		info->front = sna_dri2_reference_buffer(front);
260842542f5fSchristos		info->back = sna_dri2_reference_buffer(back);
260942542f5fSchristos
261042542f5fSchristos		if (sna->dri2.flip_pending) {
261142542f5fSchristos			/* We need to first wait (one vblank) for the
261242542f5fSchristos			 * async flips to complete before this client
261342542f5fSchristos			 * can take over.
261442542f5fSchristos			 */
261542542f5fSchristos			DBG(("%s: queueing flip after pending completion\n",
261642542f5fSchristos			     __FUNCTION__));
261742542f5fSchristos			info->type = type = FLIP;
261842542f5fSchristos			sna->dri2.flip_pending = info;
261942542f5fSchristos			assert(info->queued);
262042542f5fSchristos			current_msc++;
262142542f5fSchristos		} else {
262242542f5fSchristos			info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
262342542f5fSchristos			if (!sna_dri2_flip(sna, info)) {
262442542f5fSchristos				DBG(("%s: flip failed, falling back\n", __FUNCTION__));
262542542f5fSchristos				sna_dri2_event_free(sna, info);
262642542f5fSchristos				return false;
262742542f5fSchristos			}
262842542f5fSchristos		}
262942542f5fSchristos
263042542f5fSchristos		swap_limit(draw, 1 + (type == FLIP_THROTTLE));
263142542f5fSchristos		if (type >= FLIP_COMPLETE) {
263242542f5fSchristosnew_back:
263342542f5fSchristos			if (!xorg_can_triple_buffer(sna))
263442542f5fSchristos				sna_dri2_get_back(sna, draw, back, info);
263542542f5fSchristos			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
263642542f5fSchristos			frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
263742542f5fSchristos			if (info->type == FLIP_ASYNC)
263842542f5fSchristos				sna_dri2_event_free(sna, info);
263942542f5fSchristos		}
264042542f5fSchristosout:
264142542f5fSchristos		DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1));
264242542f5fSchristos		*target_msc = current_msc + 1;
264342542f5fSchristos		return true;
264442542f5fSchristos	}
264542542f5fSchristos
264642542f5fSchristos	info = sna_dri2_add_event(sna, draw, client);
264742542f5fSchristos	if (info == NULL)
264842542f5fSchristos		return false;
264942542f5fSchristos
265042542f5fSchristos	assert(info->crtc == crtc);
265142542f5fSchristos	info->event_complete = func;
265242542f5fSchristos	info->event_data = data;
265342542f5fSchristos	info->type = FLIP;
265442542f5fSchristos
265542542f5fSchristos	info->front = sna_dri2_reference_buffer(front);
265642542f5fSchristos	info->back = sna_dri2_reference_buffer(back);
265742542f5fSchristos
265842542f5fSchristos	/*
265942542f5fSchristos	 * If divisor is zero, or current_msc is smaller than target_msc
266042542f5fSchristos	 * we just need to make sure target_msc passes before initiating
266142542f5fSchristos	 * the swap.
266242542f5fSchristos	 */
266342542f5fSchristos	if (divisor && current_msc >= *target_msc) {
266442542f5fSchristos		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
266542542f5fSchristos		     __FUNCTION__,
266642542f5fSchristos		     (long long)current_msc,
266742542f5fSchristos		     (long long)*target_msc,
266842542f5fSchristos		     (long long)divisor,
266942542f5fSchristos		     (long long)remainder));
267042542f5fSchristos
267142542f5fSchristos		*target_msc = current_msc + remainder - current_msc % divisor;
267242542f5fSchristos		if (*target_msc <= current_msc)
267342542f5fSchristos			*target_msc += divisor;
267442542f5fSchristos	}
267542542f5fSchristos
267642542f5fSchristos	if (*target_msc <= current_msc + 1) {
267742542f5fSchristos		if (!sna_dri2_flip(sna, info)) {
267842542f5fSchristos			sna_dri2_event_free(sna, info);
267942542f5fSchristos			return false;
268042542f5fSchristos		}
268142542f5fSchristos		*target_msc = current_msc + 1;
268242542f5fSchristos	} else {
268342542f5fSchristos		union drm_wait_vblank vbl;
268442542f5fSchristos
268542542f5fSchristos		VG_CLEAR(vbl);
268642542f5fSchristos
268742542f5fSchristos		vbl.request.type =
268842542f5fSchristos			DRM_VBLANK_ABSOLUTE |
268942542f5fSchristos			DRM_VBLANK_EVENT;
269042542f5fSchristos
269142542f5fSchristos		/* Account for 1 frame extra pageflip delay */
269242542f5fSchristos		vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
269342542f5fSchristos		vbl.request.signal = (uintptr_t)info;
269442542f5fSchristos
269542542f5fSchristos		info->queued = true;
269642542f5fSchristos		if (sna_wait_vblank(sna, &vbl, info->pipe)) {
269742542f5fSchristos			sna_dri2_event_free(sna, info);
269842542f5fSchristos			return false;
269942542f5fSchristos		}
270042542f5fSchristos	}
270142542f5fSchristos
270242542f5fSchristos	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
270342542f5fSchristos	swap_limit(draw, 1);
270442542f5fSchristos	return true;
270542542f5fSchristos}
270642542f5fSchristos
270742542f5fSchristosstatic bool
270842542f5fSchristossna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
270942542f5fSchristos		       DRI2BufferPtr front, DRI2BufferPtr back,
271042542f5fSchristos		       CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
271142542f5fSchristos		       DRI2SwapEventPtr func, void *data)
271242542f5fSchristos{
271342542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
271442542f5fSchristos	uint64_t current_msc;
271542542f5fSchristos	bool sync, event;
271642542f5fSchristos
271742542f5fSchristos	if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
271842542f5fSchristos		return false;
271942542f5fSchristos
272042542f5fSchristos	sync = current_msc < *target_msc;
272142542f5fSchristos	event = dri2_chain(draw) == NULL;
272242542f5fSchristos	if (!sync || event) {
272342542f5fSchristos		DBG(("%s: performing immediate xchg on pipe %d\n",
272442542f5fSchristos		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
272542542f5fSchristos		sna_dri2_xchg(draw, front, back);
272642542f5fSchristos	}
272742542f5fSchristos	if (sync) {
272842542f5fSchristos		struct sna_dri2_event *info;
272942542f5fSchristos
273042542f5fSchristos		info = sna_dri2_add_event(sna, draw, client);
273142542f5fSchristos		if (!info)
273242542f5fSchristos			goto complete;
273342542f5fSchristos
273442542f5fSchristos		info->event_complete = func;
273542542f5fSchristos		info->event_data = data;
273642542f5fSchristos
273742542f5fSchristos		info->front = sna_dri2_reference_buffer(front);
273842542f5fSchristos		info->back = sna_dri2_reference_buffer(back);
273942542f5fSchristos		info->type = SWAP_THROTTLE;
274042542f5fSchristos
274142542f5fSchristos		if (event) {
274242542f5fSchristos			union drm_wait_vblank vbl;
274342542f5fSchristos
274442542f5fSchristos			VG_CLEAR(vbl);
274542542f5fSchristos			vbl.request.type =
274642542f5fSchristos				DRM_VBLANK_RELATIVE |
274742542f5fSchristos				DRM_VBLANK_EVENT;
274842542f5fSchristos			vbl.request.sequence = 1;
274942542f5fSchristos			vbl.request.signal = (uintptr_t)info;
275042542f5fSchristos
275142542f5fSchristos			info->queued = true;
275242542f5fSchristos			if (sna_wait_vblank(sna, &vbl, info->pipe)) {
275342542f5fSchristos				sna_dri2_event_free(sna, info);
275442542f5fSchristos				goto complete;
275542542f5fSchristos			}
275642542f5fSchristos
275742542f5fSchristos			swap_limit(draw, 2);
275842542f5fSchristos		}
275942542f5fSchristos	} else {
276042542f5fSchristoscomplete:
276142542f5fSchristos		fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
276242542f5fSchristos	}
276342542f5fSchristos
276442542f5fSchristos	*target_msc = current_msc + 1;
276542542f5fSchristos	return true;
276642542f5fSchristos}
276742542f5fSchristos
276842542f5fSchristosstatic bool
276942542f5fSchristossna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
277042542f5fSchristos			    DRI2BufferPtr front, DRI2BufferPtr back,
277142542f5fSchristos			    CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
277242542f5fSchristos			    DRI2SwapEventPtr func, void *data)
277342542f5fSchristos{
277442542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
277542542f5fSchristos	uint64_t current_msc;
277642542f5fSchristos	bool sync, event;
277742542f5fSchristos
277842542f5fSchristos	if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
277942542f5fSchristos		return false;
278042542f5fSchristos
278142542f5fSchristos	sync = current_msc < *target_msc;
278242542f5fSchristos	event = dri2_chain(draw) == NULL;
278342542f5fSchristos	if (!sync || event) {
278442542f5fSchristos		DBG(("%s: performing immediate xchg only on pipe %d\n",
278542542f5fSchristos		     __FUNCTION__, sna_crtc_to_pipe(crtc)));
278642542f5fSchristos		sna_dri2_xchg_crtc(sna, draw, crtc, front, back);
278742542f5fSchristos	}
278842542f5fSchristos	if (sync) {
278942542f5fSchristos		struct sna_dri2_event *info;
279042542f5fSchristos
279142542f5fSchristos		info = sna_dri2_add_event(sna, draw, client);
279242542f5fSchristos		if (!info)
279342542f5fSchristos			goto complete;
279442542f5fSchristos
279542542f5fSchristos		info->event_complete = func;
279642542f5fSchristos		info->event_data = data;
279742542f5fSchristos
279842542f5fSchristos		info->front = sna_dri2_reference_buffer(front);
279942542f5fSchristos		info->back = sna_dri2_reference_buffer(back);
280042542f5fSchristos		info->type = SWAP_THROTTLE;
280142542f5fSchristos
280242542f5fSchristos		if (event) {
280342542f5fSchristos			union drm_wait_vblank vbl;
280442542f5fSchristos
280542542f5fSchristos			VG_CLEAR(vbl);
280642542f5fSchristos			vbl.request.type =
280742542f5fSchristos				DRM_VBLANK_RELATIVE |
280842542f5fSchristos				DRM_VBLANK_EVENT;
280942542f5fSchristos			vbl.request.sequence = 1;
281042542f5fSchristos			vbl.request.signal = (uintptr_t)info;
281142542f5fSchristos
281242542f5fSchristos			info->queued = true;
281342542f5fSchristos			if (sna_wait_vblank(sna, &vbl, info->pipe)) {
281442542f5fSchristos				sna_dri2_event_free(sna, info);
281542542f5fSchristos				goto complete;
281642542f5fSchristos			}
281742542f5fSchristos
281842542f5fSchristos			swap_limit(draw, 2);
281942542f5fSchristos		}
282042542f5fSchristos	} else {
282142542f5fSchristoscomplete:
282242542f5fSchristos		fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
282342542f5fSchristos	}
282442542f5fSchristos
282542542f5fSchristos	*target_msc = current_msc + 1;
282642542f5fSchristos	return true;
282742542f5fSchristos}
282842542f5fSchristos
282942542f5fSchristosstatic bool has_pending_events(struct sna *sna)
283042542f5fSchristos{
283142542f5fSchristos	struct pollfd pfd;
283242542f5fSchristos	pfd.fd = sna->kgem.fd;
283342542f5fSchristos	pfd.events = POLLIN;
283442542f5fSchristos	return poll(&pfd, 1, 0) == 1;
283542542f5fSchristos}
283642542f5fSchristos
283742542f5fSchristos/*
283842542f5fSchristos * ScheduleSwap is responsible for requesting a DRM vblank event for the
283942542f5fSchristos * appropriate frame.
284042542f5fSchristos *
284142542f5fSchristos * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
284242542f5fSchristos * the vblank requested can simply be the last queued swap frame + the swap
284342542f5fSchristos * interval for the drawable.
284442542f5fSchristos *
284542542f5fSchristos * In the case of a page flip, we request an event for the last queued swap
284642542f5fSchristos * frame + swap interval - 1, since we'll need to queue the flip for the frame
284742542f5fSchristos * immediately following the received event.
284842542f5fSchristos *
284942542f5fSchristos * The client will be blocked if it tries to perform further GL commands
285042542f5fSchristos * after queueing a swap, though in the Intel case after queueing a flip, the
285142542f5fSchristos * client is free to queue more commands; they'll block in the kernel if
285242542f5fSchristos * they access buffers busy with the flip.
285342542f5fSchristos *
285442542f5fSchristos * When the swap is complete, the driver should call into the server so it
285542542f5fSchristos * can send any swap complete events that have been requested.
285642542f5fSchristos */
285742542f5fSchristosstatic int
285842542f5fSchristossna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
285942542f5fSchristos		       DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
286042542f5fSchristos		       CARD64 remainder, DRI2SwapEventPtr func, void *data)
286142542f5fSchristos{
286242542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
286342542f5fSchristos	union drm_wait_vblank vbl;
286442542f5fSchristos	xf86CrtcPtr crtc = NULL;
286542542f5fSchristos	struct sna_dri2_event *info = NULL;
286642542f5fSchristos	CARD64 current_msc;
286742542f5fSchristos
286842542f5fSchristos	DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n",
286942542f5fSchristos	     __FUNCTION__,
287042542f5fSchristos	     (long)draw->id, draw->width, draw->height,
287142542f5fSchristos	     get_drawable_pixmap(draw)->drawable.serialNumber,
287242542f5fSchristos	     get_drawable_pixmap(draw)->drawable.width,
287342542f5fSchristos	     get_drawable_pixmap(draw)->drawable.height,
287442542f5fSchristos	     get_private(back)->bo->handle,
287542542f5fSchristos	     get_private(back)->refcnt,
287642542f5fSchristos	     get_private(back)->bo->refcnt,
287742542f5fSchristos	     get_private(back)->bo->flush,
287842542f5fSchristos	     get_private(front)->bo->handle,
287942542f5fSchristos	     get_private(front)->refcnt,
288042542f5fSchristos	     get_private(front)->bo->refcnt,
288142542f5fSchristos	     get_private(front)->bo->flush));
288242542f5fSchristos
288342542f5fSchristos	DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n",
288442542f5fSchristos	     __FUNCTION__,
288542542f5fSchristos	     (long long)*target_msc,
288642542f5fSchristos	     (long long)divisor,
288742542f5fSchristos	     (long long)remainder));
288842542f5fSchristos
288942542f5fSchristos	assert(get_private(front)->refcnt);
289042542f5fSchristos	assert(get_private(back)->refcnt);
289142542f5fSchristos
289242542f5fSchristos	assert(get_private(front)->bo->refcnt);
289342542f5fSchristos	assert(get_private(back)->bo->refcnt);
289442542f5fSchristos
289542542f5fSchristos	if (get_private(front)->pixmap != get_drawable_pixmap(draw))
289642542f5fSchristos		goto skip;
289742542f5fSchristos
289842542f5fSchristos	if (get_private(back)->stale)
289942542f5fSchristos		goto skip;
290042542f5fSchristos
290142542f5fSchristos	assert(sna_pixmap_from_drawable(draw)->flush);
290242542f5fSchristos
290342542f5fSchristos	if (draw->type != DRAWABLE_PIXMAP) {
290442542f5fSchristos		WindowPtr win = (WindowPtr)draw;
290542542f5fSchristos		struct dri2_window *priv = dri2_window(win);
290642542f5fSchristos		if (priv->front) {
290742542f5fSchristos			assert(front == priv->front);
290842542f5fSchristos			assert(get_private(priv->front)->refcnt > 1);
290942542f5fSchristos			get_private(priv->front)->refcnt--;
291042542f5fSchristos			priv->front = NULL;
291142542f5fSchristos		}
291242542f5fSchristos		if (win->clipList.extents.x2 <= win->clipList.extents.x1 ||
291342542f5fSchristos		    win->clipList.extents.y2 <= win->clipList.extents.y1)
291442542f5fSchristos			goto skip;
291542542f5fSchristos	}
291642542f5fSchristos
291742542f5fSchristos	/* Drawable not displayed... just complete the swap */
291842542f5fSchristos	if ((sna->flags & SNA_NO_WAIT) == 0)
291942542f5fSchristos		crtc = sna_dri2_get_crtc(draw);
292042542f5fSchristos	if (crtc == NULL) {
292142542f5fSchristos		DBG(("%s: off-screen, immediate update\n", __FUNCTION__));
292242542f5fSchristos		goto blit;
292342542f5fSchristos	}
292442542f5fSchristos
292542542f5fSchristos	assert(draw->type != DRAWABLE_PIXMAP);
292642542f5fSchristos
292742542f5fSchristos	while (dri2_chain(draw) && has_pending_events(sna)) {
292842542f5fSchristos		DBG(("%s: flushing pending events\n", __FUNCTION__));
292942542f5fSchristos		sna_mode_wakeup(sna);
293042542f5fSchristos	}
293142542f5fSchristos
293242542f5fSchristos	if (can_xchg(sna, draw, front, back) &&
293342542f5fSchristos	    sna_dri2_schedule_xchg(client, draw, crtc, front, back,
293442542f5fSchristos				   target_msc, divisor, remainder,
293542542f5fSchristos				   func, data))
293642542f5fSchristos		return TRUE;
293742542f5fSchristos
293842542f5fSchristos	if (can_xchg_crtc(sna, draw, front, back, crtc) &&
293942542f5fSchristos	    sna_dri2_schedule_xchg_crtc(client, draw, crtc, front, back,
294042542f5fSchristos					target_msc, divisor, remainder,
294142542f5fSchristos					func, data))
294242542f5fSchristos		return TRUE;
294342542f5fSchristos
294442542f5fSchristos	if (can_flip(sna, draw, front, back, crtc) &&
294542542f5fSchristos	    sna_dri2_schedule_flip(client, draw, crtc, front, back,
294642542f5fSchristos				  target_msc, divisor, remainder,
294742542f5fSchristos				  func, data))
294842542f5fSchristos		return TRUE;
294942542f5fSchristos
295042542f5fSchristos	VG_CLEAR(vbl);
295142542f5fSchristos
295242542f5fSchristos	info = sna_dri2_add_event(sna, draw, client);
295342542f5fSchristos	if (!info)
295442542f5fSchristos		goto blit;
295542542f5fSchristos
295642542f5fSchristos	assert(info->crtc == crtc);
295742542f5fSchristos	info->event_complete = func;
295842542f5fSchristos	info->event_data = data;
295942542f5fSchristos
296042542f5fSchristos	info->front = sna_dri2_reference_buffer(front);
296142542f5fSchristos	info->back = sna_dri2_reference_buffer(back);
296242542f5fSchristos
296342542f5fSchristos	if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
296442542f5fSchristos		bool sync = current_msc < *target_msc;
296542542f5fSchristos		if (!sna_dri2_immediate_blit(sna, info, sync, true))
296642542f5fSchristos			sna_dri2_event_free(sna, info);
296742542f5fSchristos		*target_msc = current_msc + sync;
296842542f5fSchristos		return TRUE;
296942542f5fSchristos	}
297042542f5fSchristos
297142542f5fSchristos	vbl.request.type =
297242542f5fSchristos		DRM_VBLANK_ABSOLUTE |
297342542f5fSchristos		DRM_VBLANK_EVENT;
297442542f5fSchristos	vbl.request.signal = (uintptr_t)info;
297542542f5fSchristos
297642542f5fSchristos	/*
297742542f5fSchristos	 * If divisor is zero, or current_msc is smaller than target_msc
297842542f5fSchristos	 * we just need to make sure target_msc passes before initiating
297942542f5fSchristos	 * the swap.
298042542f5fSchristos	 */
298142542f5fSchristos	info->type = SWAP;
298242542f5fSchristos	info->queued = true;
298342542f5fSchristos	if (divisor && current_msc >= *target_msc) {
298442542f5fSchristos		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
298542542f5fSchristos		     __FUNCTION__,
298642542f5fSchristos		     (long long)current_msc,
298742542f5fSchristos		     (long long)*target_msc,
298842542f5fSchristos		     (long long)divisor,
298942542f5fSchristos		     (long long)remainder));
299042542f5fSchristos
299142542f5fSchristos		*target_msc = current_msc + remainder - current_msc % divisor;
299242542f5fSchristos		if (*target_msc <= current_msc)
299342542f5fSchristos			*target_msc += divisor;
299442542f5fSchristos	}
299542542f5fSchristos	vbl.request.sequence = draw_target_seq(draw, *target_msc - 1);
299642542f5fSchristos	if (*target_msc <= current_msc + 1) {
299742542f5fSchristos		DBG(("%s: performing blit before queueing\n", __FUNCTION__));
299842542f5fSchristos		assert(info->queued);
299942542f5fSchristos		info->bo = __sna_dri2_copy_region(sna, draw, NULL,
300042542f5fSchristos						  back, front,
300142542f5fSchristos						  true);
300242542f5fSchristos		info->type = SWAP_WAIT;
300342542f5fSchristos
300442542f5fSchristos		vbl.request.type =
300542542f5fSchristos			DRM_VBLANK_RELATIVE |
300642542f5fSchristos			DRM_VBLANK_EVENT;
300742542f5fSchristos		vbl.request.sequence = 1;
300842542f5fSchristos		*target_msc = current_msc + 1;
300942542f5fSchristos	}
301042542f5fSchristos
301142542f5fSchristos	assert(info->queued);
301242542f5fSchristos	if (sna_wait_vblank(sna, &vbl, info->pipe))
301342542f5fSchristos		goto blit;
301442542f5fSchristos
301542542f5fSchristos	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
301642542f5fSchristos	swap_limit(draw, 1 + (info->type == SWAP_WAIT));
301742542f5fSchristos	return TRUE;
301842542f5fSchristos
301942542f5fSchristosblit:
302042542f5fSchristos	DBG(("%s -- blit\n", __FUNCTION__));
302142542f5fSchristos	if (info)
302242542f5fSchristos		sna_dri2_event_free(sna, info);
302342542f5fSchristos	if (can_xchg(sna, draw, front, back))
302442542f5fSchristos		sna_dri2_xchg(draw, front, back);
302542542f5fSchristos	else
302642542f5fSchristos		__sna_dri2_copy_region(sna, draw, NULL, back, front, false);
302742542f5fSchristosskip:
302842542f5fSchristos	DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
302942542f5fSchristos	if (crtc == NULL)
303042542f5fSchristos		crtc = sna_mode_first_crtc(sna);
303142542f5fSchristos	fake_swap_complete(sna, client, draw, crtc, DRI2_BLIT_COMPLETE, func, data);
303242542f5fSchristos	*target_msc = 0; /* offscreen, so zero out target vblank count */
303342542f5fSchristos	return TRUE;
303442542f5fSchristos}
303542542f5fSchristos
303642542f5fSchristos/*
303742542f5fSchristos * Get current frame count and frame count timestamp, based on drawable's
303842542f5fSchristos * crtc.
303942542f5fSchristos */
304042542f5fSchristosstatic int
304142542f5fSchristossna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
304242542f5fSchristos{
304342542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
304442542f5fSchristos	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
304542542f5fSchristos	const struct ust_msc *swap;
304642542f5fSchristos
304742542f5fSchristos	DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
304842542f5fSchristos	     crtc ? sna_crtc_to_pipe(crtc) : -1));
304942542f5fSchristos
305042542f5fSchristos	if (crtc != NULL) {
305142542f5fSchristos		union drm_wait_vblank vbl;
305242542f5fSchristos
305342542f5fSchristos		VG_CLEAR(vbl);
305442542f5fSchristos		vbl.request.type = _DRM_VBLANK_RELATIVE;
305542542f5fSchristos		vbl.request.sequence = 0;
305642542f5fSchristos		if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
305742542f5fSchristos			sna_crtc_record_vblank(crtc, &vbl);
305842542f5fSchristos	} else
305942542f5fSchristos		/* Drawable not displayed, make up a *monotonic* value */
306042542f5fSchristos		crtc = sna_mode_first_crtc(sna);
306142542f5fSchristos
306242542f5fSchristos	swap = sna_crtc_last_swap(crtc);
306342542f5fSchristos	*msc = draw_current_msc(draw, crtc, swap->msc);
306442542f5fSchristos	*ust = ust64(swap->tv_sec, swap->tv_usec);
306542542f5fSchristos	DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
306642542f5fSchristos	     (long long)*msc, (long long)*ust));
306742542f5fSchristos	return TRUE;
306842542f5fSchristos}
306942542f5fSchristos
307042542f5fSchristos/*
307142542f5fSchristos * Request a DRM event when the requested conditions will be satisfied.
307242542f5fSchristos *
307342542f5fSchristos * We need to handle the event and ask the server to wake up the client when
307442542f5fSchristos * we receive it.
307542542f5fSchristos */
307642542f5fSchristosstatic int
307742542f5fSchristossna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
307842542f5fSchristos			   CARD64 divisor, CARD64 remainder)
307942542f5fSchristos{
308042542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
308142542f5fSchristos	struct sna_dri2_event *info = NULL;
308242542f5fSchristos	xf86CrtcPtr crtc;
308342542f5fSchristos	CARD64 current_msc;
308442542f5fSchristos	union drm_wait_vblank vbl;
308542542f5fSchristos	const struct ust_msc *swap;
308642542f5fSchristos	int pipe;
308742542f5fSchristos
308842542f5fSchristos	crtc = sna_dri2_get_crtc(draw);
308942542f5fSchristos	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
309042542f5fSchristos	     __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
309142542f5fSchristos	     (long long)target_msc,
309242542f5fSchristos	     (long long)divisor,
309342542f5fSchristos	     (long long)remainder));
309442542f5fSchristos
309542542f5fSchristos	/* Drawable not visible, return immediately */
309642542f5fSchristos	if (crtc == NULL)
309742542f5fSchristos		goto out_complete;
309842542f5fSchristos
309942542f5fSchristos	pipe = sna_crtc_to_pipe(crtc);
310042542f5fSchristos
310142542f5fSchristos	VG_CLEAR(vbl);
310242542f5fSchristos
310342542f5fSchristos	/* Get current count */
310442542f5fSchristos	vbl.request.type = _DRM_VBLANK_RELATIVE;
310542542f5fSchristos	vbl.request.sequence = 0;
310642542f5fSchristos	if (sna_wait_vblank(sna, &vbl, pipe))
310742542f5fSchristos		goto out_complete;
310842542f5fSchristos
310942542f5fSchristos	current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
311042542f5fSchristos
311142542f5fSchristos	/* If target_msc already reached or passed, set it to
311242542f5fSchristos	 * current_msc to ensure we return a reasonable value back
311342542f5fSchristos	 * to the caller. This keeps the client from continually
311442542f5fSchristos	 * sending us MSC targets from the past by forcibly updating
311542542f5fSchristos	 * their count on this call.
311642542f5fSchristos	 */
311742542f5fSchristos	if (divisor == 0 && current_msc >= target_msc)
311842542f5fSchristos		goto out_complete;
311942542f5fSchristos
312042542f5fSchristos	info = sna_dri2_add_event(sna, draw, client);
312142542f5fSchristos	if (!info)
312242542f5fSchristos		goto out_complete;
312342542f5fSchristos
312442542f5fSchristos	assert(info->crtc == crtc);
312542542f5fSchristos	info->type = WAITMSC;
312642542f5fSchristos
312742542f5fSchristos	vbl.request.signal = (uintptr_t)info;
312842542f5fSchristos	vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
312942542f5fSchristos	/*
313042542f5fSchristos	 * If divisor is zero, or current_msc is smaller than target_msc,
313142542f5fSchristos	 * we just need to make sure target_msc passes before waking up the
313242542f5fSchristos	 * client. Otherwise, compute the next msc to match divisor/remainder.
313342542f5fSchristos	 */
313442542f5fSchristos	if (divisor && current_msc >= target_msc) {
313542542f5fSchristos		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
313642542f5fSchristos		     __FUNCTION__,
313742542f5fSchristos		     (long long)current_msc,
313842542f5fSchristos		     (long long)target_msc,
313942542f5fSchristos		     (long long)divisor,
314042542f5fSchristos		     (long long)remainder));
314142542f5fSchristos		target_msc = current_msc + remainder - current_msc % divisor;
314242542f5fSchristos		if (target_msc <= current_msc)
314342542f5fSchristos			target_msc += divisor;
314442542f5fSchristos	}
314542542f5fSchristos	vbl.request.sequence = draw_target_seq(draw, target_msc);
314642542f5fSchristos
314742542f5fSchristos	info->queued = true;
314842542f5fSchristos	if (sna_wait_vblank(sna, &vbl, pipe))
314942542f5fSchristos		goto out_free_info;
315042542f5fSchristos
315142542f5fSchristos	DRI2BlockClient(client, draw);
315242542f5fSchristos	return TRUE;
315342542f5fSchristos
315442542f5fSchristosout_free_info:
315542542f5fSchristos	sna_dri2_event_free(sna, info);
315642542f5fSchristosout_complete:
315742542f5fSchristos	if (crtc == NULL)
315842542f5fSchristos		crtc = sna_mode_first_crtc(sna);
315942542f5fSchristos	swap = sna_crtc_last_swap(crtc);
316042542f5fSchristos	DRI2WaitMSCComplete(client, draw,
316142542f5fSchristos			    draw_current_msc(draw, crtc, swap->msc),
316242542f5fSchristos			    swap->tv_sec, swap->tv_usec);
316342542f5fSchristos	return TRUE;
316442542f5fSchristos}
316542542f5fSchristos#else
316642542f5fSchristosvoid sna_dri2_destroy_window(WindowPtr win) { }
316742542f5fSchristos#endif
316842542f5fSchristos
316942542f5fSchristosstatic bool has_i830_dri(void)
317042542f5fSchristos{
317142542f5fSchristos	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
317242542f5fSchristos}
317342542f5fSchristos
317442542f5fSchristosstatic int
317542542f5fSchristosnamecmp(const char *s1, const char *s2)
317642542f5fSchristos{
317742542f5fSchristos	char c1, c2;
317842542f5fSchristos
317942542f5fSchristos	if (!s1 || *s1 == 0) {
318042542f5fSchristos		if (!s2 || *s2 == 0)
318142542f5fSchristos			return 0;
318242542f5fSchristos		else
318342542f5fSchristos			return 1;
318442542f5fSchristos	}
318542542f5fSchristos
318642542f5fSchristos	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
318742542f5fSchristos		s1++;
318842542f5fSchristos
318942542f5fSchristos	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
319042542f5fSchristos		s2++;
319142542f5fSchristos
319242542f5fSchristos	c1 = isupper(*s1) ? tolower(*s1) : *s1;
319342542f5fSchristos	c2 = isupper(*s2) ? tolower(*s2) : *s2;
319442542f5fSchristos	while (c1 == c2) {
319542542f5fSchristos		if (c1 == '\0')
319642542f5fSchristos			return 0;
319742542f5fSchristos
319842542f5fSchristos		s1++;
319942542f5fSchristos		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
320042542f5fSchristos			s1++;
320142542f5fSchristos
320242542f5fSchristos		s2++;
320342542f5fSchristos		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
320442542f5fSchristos			s2++;
320542542f5fSchristos
320642542f5fSchristos		c1 = isupper(*s1) ? tolower(*s1) : *s1;
320742542f5fSchristos		c2 = isupper(*s2) ? tolower(*s2) : *s2;
320842542f5fSchristos	}
320942542f5fSchristos
321042542f5fSchristos	return c1 - c2;
321142542f5fSchristos}
321242542f5fSchristos
321342542f5fSchristosstatic bool is_level(const char **str)
321442542f5fSchristos{
321542542f5fSchristos	const char *s = *str;
321642542f5fSchristos	char *end;
321742542f5fSchristos	unsigned val;
321842542f5fSchristos
321942542f5fSchristos	if (s == NULL || *s == '\0')
322042542f5fSchristos		return true;
322142542f5fSchristos
322242542f5fSchristos	if (namecmp(s, "on") == 0)
322342542f5fSchristos		return true;
322442542f5fSchristos	if (namecmp(s, "true") == 0)
322542542f5fSchristos		return true;
322642542f5fSchristos	if (namecmp(s, "yes") == 0)
322742542f5fSchristos		return true;
322842542f5fSchristos
322942542f5fSchristos	if (namecmp(s, "0") == 0)
323042542f5fSchristos		return true;
323142542f5fSchristos	if (namecmp(s, "off") == 0)
323242542f5fSchristos		return true;
323342542f5fSchristos	if (namecmp(s, "false") == 0)
323442542f5fSchristos		return true;
323542542f5fSchristos	if (namecmp(s, "no") == 0)
323642542f5fSchristos		return true;
323742542f5fSchristos
323842542f5fSchristos	val = strtoul(s, &end, 0);
323942542f5fSchristos	if (val && *end == '\0')
324042542f5fSchristos		return true;
324142542f5fSchristos	if (val && *end == ':')
324242542f5fSchristos		*str = end + 1;
324342542f5fSchristos	return false;
324442542f5fSchristos}
324542542f5fSchristos
324642542f5fSchristosstatic const char *dri_driver_name(struct sna *sna)
324742542f5fSchristos{
324842542f5fSchristos	const char *s = xf86GetOptValString(sna->Options, OPTION_DRI);
324942542f5fSchristos
325042542f5fSchristos	if (is_level(&s)) {
325142542f5fSchristos		if (sna->kgem.gen < 030)
325242542f5fSchristos			return has_i830_dri() ? "i830" : "i915";
325342542f5fSchristos		else if (sna->kgem.gen < 040)
325442542f5fSchristos			return "i915";
325542542f5fSchristos		else
325642542f5fSchristos			return "i965";
325742542f5fSchristos	}
325842542f5fSchristos
325942542f5fSchristos	return s;
326042542f5fSchristos}
326142542f5fSchristos
326242542f5fSchristosbool sna_dri2_open(struct sna *sna, ScreenPtr screen)
326342542f5fSchristos{
326442542f5fSchristos	DRI2InfoRec info;
326542542f5fSchristos	int major = 1, minor = 0;
326642542f5fSchristos#if DRI2INFOREC_VERSION >= 4
326742542f5fSchristos	const char *driverNames[2];
326842542f5fSchristos#endif
326942542f5fSchristos
327042542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
327142542f5fSchristos
327242542f5fSchristos	if (wedged(sna)) {
327342542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
327442542f5fSchristos			   "loading DRI2 whilst the GPU is wedged.\n");
327542542f5fSchristos	}
327642542f5fSchristos
327742542f5fSchristos	if (xf86LoaderCheckSymbol("DRI2Version"))
327842542f5fSchristos		DRI2Version(&major, &minor);
327942542f5fSchristos
328042542f5fSchristos	if (minor < 1) {
328142542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
328242542f5fSchristos			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
328342542f5fSchristos		return false;
328442542f5fSchristos	}
328542542f5fSchristos
328642542f5fSchristos	memset(&info, '\0', sizeof(info));
328742542f5fSchristos	info.fd = sna->kgem.fd;
328842542f5fSchristos	info.driverName = dri_driver_name(sna);
328942542f5fSchristos	info.deviceName = intel_get_client_name(sna->scrn);
329042542f5fSchristos
329142542f5fSchristos	DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
329242542f5fSchristos	     __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
329342542f5fSchristos
329442542f5fSchristos#if DRI2INFOREC_VERSION == 2
329542542f5fSchristos	/* The ABI between 2 and 3 was broken so we could get rid of
329642542f5fSchristos	 * the multi-buffer alloc functions.  Make sure we indicate the
329742542f5fSchristos	 * right version so DRI2 can reject us if it's version 3 or above. */
329842542f5fSchristos	info.version = 2;
329942542f5fSchristos#else
330042542f5fSchristos	info.version = 3;
330142542f5fSchristos#endif
330242542f5fSchristos	info.CreateBuffer = sna_dri2_create_buffer;
330342542f5fSchristos	info.DestroyBuffer = sna_dri2_destroy_buffer;
330442542f5fSchristos
330542542f5fSchristos	info.CopyRegion = sna_dri2_copy_region;
330642542f5fSchristos#if DRI2INFOREC_VERSION >= 4
330742542f5fSchristos	info.version = 4;
330842542f5fSchristos	info.ScheduleSwap = sna_dri2_schedule_swap;
330942542f5fSchristos	info.GetMSC = sna_dri2_get_msc;
331042542f5fSchristos	info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc;
331142542f5fSchristos	info.numDrivers = 2;
331242542f5fSchristos	info.driverNames = driverNames;
331342542f5fSchristos	driverNames[0] = info.driverName;
331442542f5fSchristos	driverNames[1] = info.driverName;
331542542f5fSchristos#endif
331642542f5fSchristos
331742542f5fSchristos#if DRI2INFOREC_VERSION >= 6
331842542f5fSchristos	if (xorg_can_triple_buffer(sna)) {
331942542f5fSchristos		info.version = 6;
332042542f5fSchristos		info.SwapLimitValidate = sna_dri2_swap_limit_validate;
332142542f5fSchristos		info.ReuseBufferNotify = sna_dri2_reuse_buffer;
332242542f5fSchristos	}
332342542f5fSchristos#endif
332442542f5fSchristos
332542542f5fSchristos#if USE_ASYNC_SWAP
332642542f5fSchristos	info.version = 10;
332742542f5fSchristos	info.scheduleSwap0 = 1;
332842542f5fSchristos#endif
332942542f5fSchristos
333042542f5fSchristos	return DRI2ScreenInit(screen, &info);
333142542f5fSchristos}
333242542f5fSchristos
333342542f5fSchristosvoid sna_dri2_close(struct sna *sna, ScreenPtr screen)
333442542f5fSchristos{
333542542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
333642542f5fSchristos	DRI2CloseScreen(screen);
333742542f5fSchristos}
3338