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{
6713496ba1Ssnj	return kgem_bo_reference(bo);
6842542f5fSchristos}
6942542f5fSchristos
7042542f5fSchristosstruct sna_dri2_private {
7142542f5fSchristos	PixmapPtr pixmap;
7242542f5fSchristos	struct kgem_bo *bo;
7342542f5fSchristos	DRI2Buffer2Ptr proxy;
7442542f5fSchristos	bool stale;
7542542f5fSchristos	uint32_t size;
7642542f5fSchristos	int refcnt;
7742542f5fSchristos};
7842542f5fSchristos
7942542f5fSchristosstatic inline struct sna_dri2_private *
8042542f5fSchristosget_private(void *buffer)
8142542f5fSchristos{
8242542f5fSchristos	return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
8342542f5fSchristos}
8442542f5fSchristos
8563ef14f0Smrgpure static inline DRI2BufferPtr sna_pixmap_get_buffer(PixmapPtr pixmap)
8663ef14f0Smrg{
8763ef14f0Smrg	assert(pixmap->refcnt);
8863ef14f0Smrg	return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
8963ef14f0Smrg}
9063ef14f0Smrg
9163ef14f0Smrgstatic inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
9263ef14f0Smrg{
9363ef14f0Smrg	assert(pixmap->refcnt);
9463ef14f0Smrg	((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
9563ef14f0Smrg}
9663ef14f0Smrg
9742542f5fSchristos#if DRI2INFOREC_VERSION >= 4
9842542f5fSchristosenum event_type {
9942542f5fSchristos	WAITMSC = 0,
10042542f5fSchristos	SWAP,
10163ef14f0Smrg	SWAP_COMPLETE,
10242542f5fSchristos	FLIP,
10342542f5fSchristos	FLIP_THROTTLE,
10442542f5fSchristos	FLIP_COMPLETE,
10542542f5fSchristos	FLIP_ASYNC,
10642542f5fSchristos};
10742542f5fSchristos
10842542f5fSchristosstruct dri_bo {
10942542f5fSchristos	struct list link;
11042542f5fSchristos	struct kgem_bo *bo;
11142542f5fSchristos	uint32_t name;
11263ef14f0Smrg	unsigned flags;
11342542f5fSchristos};
11442542f5fSchristos
11542542f5fSchristosstruct sna_dri2_event {
11613496ba1Ssnj	struct sna *sna;
11742542f5fSchristos	DrawablePtr draw;
11842542f5fSchristos	ClientPtr client;
11942542f5fSchristos	enum event_type type;
12042542f5fSchristos	xf86CrtcPtr crtc;
12142542f5fSchristos	int pipe;
12242542f5fSchristos	bool queued;
12363ef14f0Smrg	bool sync;
12463ef14f0Smrg	bool chained;
12542542f5fSchristos
12642542f5fSchristos	/* for swaps & flips only */
12742542f5fSchristos	DRI2SwapEventPtr event_complete;
12842542f5fSchristos	void *event_data;
12942542f5fSchristos	DRI2BufferPtr front;
13042542f5fSchristos	DRI2BufferPtr back;
13142542f5fSchristos	struct kgem_bo *bo;
13242542f5fSchristos
13363ef14f0Smrg	struct copy {
13463ef14f0Smrg		struct kgem_bo *bo;
13563ef14f0Smrg		unsigned flags;
13663ef14f0Smrg		uint32_t name;
13763ef14f0Smrg		uint32_t size;
13863ef14f0Smrg	} pending;
13963ef14f0Smrg
14042542f5fSchristos	struct sna_dri2_event *chain;
14142542f5fSchristos
14242542f5fSchristos	struct list link;
14342542f5fSchristos
14463ef14f0Smrg	int flip_continue;
14563ef14f0Smrg	int keepalive;
14663ef14f0Smrg	int signal;
14742542f5fSchristos};
14842542f5fSchristos
14963ef14f0Smrg#if DRI2INFOREC_VERSION < 10
15063ef14f0Smrg#undef USE_ASYNC_SWAP
15163ef14f0Smrg#endif
15263ef14f0Smrg
15363ef14f0Smrg#if USE_ASYNC_SWAP
15463ef14f0Smrg#define KEEPALIVE 8 /* wait ~100ms before discarding swap caches */
15563ef14f0Smrg#define APPLY_DAMAGE 0
15663ef14f0Smrg#else
15763ef14f0Smrg#define USE_ASYNC_SWAP 0
15863ef14f0Smrg#define KEEPALIVE 1
15963ef14f0Smrg#define APPLY_DAMAGE 1
16063ef14f0Smrg#endif
16163ef14f0Smrg
16213496ba1Ssnjstatic void sna_dri2_flip_event(struct sna_dri2_event *flip);
16363ef14f0Smrginline static DRI2BufferPtr dri2_window_get_front(WindowPtr win);
16463ef14f0Smrg
16563ef14f0Smrgstatic struct kgem_bo *
16663ef14f0Smrg__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
16763ef14f0Smrg		      DRI2BufferPtr src, DRI2BufferPtr dst,
16863ef14f0Smrg		      unsigned flags);
16963ef14f0Smrg
17063ef14f0Smrginline static void
17163ef14f0Smrg__sna_dri2_copy_event(struct sna_dri2_event *info, unsigned flags)
17263ef14f0Smrg{
17363ef14f0Smrg	DBG(("%s: flags = %x\n", __FUNCTION__, flags));
17463ef14f0Smrg	assert(info->front != info->back);
17563ef14f0Smrg	info->bo = __sna_dri2_copy_region(info->sna, info->draw, NULL,
17663ef14f0Smrg					  info->back, info->front,
17763ef14f0Smrg					  flags);
17863ef14f0Smrg	info->front->flags = info->back->flags;
17963ef14f0Smrg}
18063ef14f0Smrg
18163ef14f0Smrgstatic int front_pitch(DrawablePtr draw)
18263ef14f0Smrg{
18363ef14f0Smrg	DRI2BufferPtr buffer;
18463ef14f0Smrg
18563ef14f0Smrg	buffer = NULL;
18663ef14f0Smrg	if (draw->type != DRAWABLE_PIXMAP)
18763ef14f0Smrg		buffer = dri2_window_get_front((WindowPtr)draw);
18863ef14f0Smrg	if (buffer == NULL)
18963ef14f0Smrg		buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
19063ef14f0Smrg
19163ef14f0Smrg	return buffer ? buffer->pitch : 0;
19263ef14f0Smrg}
19363ef14f0Smrg
19463ef14f0Smrgstruct dri2_window {
19563ef14f0Smrg	DRI2BufferPtr front;
19663ef14f0Smrg	struct sna_dri2_event *chain;
19763ef14f0Smrg	xf86CrtcPtr crtc;
19863ef14f0Smrg	int64_t msc_delta;
19963ef14f0Smrg	struct list cache;
20063ef14f0Smrg	uint32_t cache_size;
20163ef14f0Smrg};
20263ef14f0Smrg
20363ef14f0Smrgstatic struct dri2_window *dri2_window(WindowPtr win)
20463ef14f0Smrg{
20563ef14f0Smrg	assert(win->drawable.type != DRAWABLE_PIXMAP);
20663ef14f0Smrg	return ((void **)__get_private(win, sna_window_key))[1];
20763ef14f0Smrg}
20863ef14f0Smrg
20963ef14f0Smrgstatic bool use_scanout(struct sna *sna,
21063ef14f0Smrg			DrawablePtr draw,
21163ef14f0Smrg			struct dri2_window *priv)
21263ef14f0Smrg{
21363ef14f0Smrg	if (priv->front)
21463ef14f0Smrg		return true;
21563ef14f0Smrg
21663ef14f0Smrg	return (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0 &&
21763ef14f0Smrg		draw->width  == sna->front->drawable.width &&
21863ef14f0Smrg		draw->height == sna->front->drawable.height &&
21963ef14f0Smrg		draw->bitsPerPixel == sna->front->drawable.bitsPerPixel;
22063ef14f0Smrg}
22142542f5fSchristos
22242542f5fSchristosstatic void
22342542f5fSchristossna_dri2_get_back(struct sna *sna,
22442542f5fSchristos		  DrawablePtr draw,
22563ef14f0Smrg		  DRI2BufferPtr back)
22642542f5fSchristos{
22763ef14f0Smrg	struct dri2_window *priv = dri2_window((WindowPtr)draw);
22863ef14f0Smrg	uint32_t size;
22942542f5fSchristos	struct kgem_bo *bo;
23063ef14f0Smrg	struct dri_bo *c;
23142542f5fSchristos	uint32_t name;
23263ef14f0Smrg	int flags;
23342542f5fSchristos	bool reuse;
23442542f5fSchristos
23563ef14f0Smrg	DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, active?=%d, pitch=%d, front pitch=%d\n",
23642542f5fSchristos	     __FUNCTION__, draw->width, draw->height,
23763ef14f0Smrg	     get_private(back)->bo->handle,
23863ef14f0Smrg	     get_private(back)->size & 0xffff, get_private(back)->size >> 16,
23963ef14f0Smrg	     get_private(back)->bo->scanout,
24063ef14f0Smrg	     get_private(back)->bo->active_scanout,
24163ef14f0Smrg	     back->pitch, front_pitch(draw)));
24263ef14f0Smrg	assert(priv);
24363ef14f0Smrg
24463ef14f0Smrg	size = draw->height << 16 | draw->width;
24563ef14f0Smrg	if (size != priv->cache_size) {
24663ef14f0Smrg		while (!list_is_empty(&priv->cache)) {
24763ef14f0Smrg			c = list_first_entry(&priv->cache, struct dri_bo, link);
24863ef14f0Smrg			list_del(&c->link);
24963ef14f0Smrg
25063ef14f0Smrg			DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
25163ef14f0Smrg			assert(c->bo);
25263ef14f0Smrg			kgem_bo_destroy(&sna->kgem, c->bo);
25363ef14f0Smrg
25463ef14f0Smrg			free(c);
25563ef14f0Smrg		}
25663ef14f0Smrg		priv->cache_size = size;
25763ef14f0Smrg	}
25863ef14f0Smrg
25963ef14f0Smrg	reuse = size == get_private(back)->size;
26063ef14f0Smrg	if (reuse)
26163ef14f0Smrg		reuse = get_private(back)->bo->scanout == use_scanout(sna, draw, priv);
26263ef14f0Smrg	DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse));
26342542f5fSchristos	if (reuse) {
26442542f5fSchristos		bo = get_private(back)->bo;
26542542f5fSchristos		assert(bo->refcnt);
26663ef14f0Smrg		DBG(("%s: back buffer handle=%d, active?=%d, refcnt=%d\n",
26763ef14f0Smrg		     __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
26842542f5fSchristos		if (bo->active_scanout == 0) {
26942542f5fSchristos			DBG(("%s: reuse unattached back\n", __FUNCTION__));
27042542f5fSchristos			get_private(back)->stale = false;
27142542f5fSchristos			return;
27242542f5fSchristos		}
27342542f5fSchristos	}
27442542f5fSchristos
27542542f5fSchristos	bo = NULL;
27663ef14f0Smrg	list_for_each_entry(c, &priv->cache, link) {
27763ef14f0Smrg		DBG(("%s: cache: handle=%d, active=%d\n",
27863ef14f0Smrg		     __FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
27963ef14f0Smrg		assert(c->bo);
28063ef14f0Smrg		if (c->bo->active_scanout == 0) {
28163ef14f0Smrg			_list_del(&c->link);
28263ef14f0Smrg			if (c->bo == NULL) {
28363ef14f0Smrg				free(c);
28463ef14f0Smrg				goto out;
28542542f5fSchristos			}
28663ef14f0Smrg			bo = c->bo;
28763ef14f0Smrg			name = c->name;
28863ef14f0Smrg			flags = c->flags;
28963ef14f0Smrg			DBG(("%s: reuse cache handle=%d, name=%d, flags=%d\n", __FUNCTION__, bo->handle, name, flags));
29063ef14f0Smrg			c->bo = NULL;
29163ef14f0Smrg			break;
29242542f5fSchristos		}
29342542f5fSchristos	}
29442542f5fSchristos	if (bo == NULL) {
29542542f5fSchristos		DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
29663ef14f0Smrg		flags = CREATE_EXACT;
29763ef14f0Smrg
29863ef14f0Smrg		if (get_private(back)->bo->scanout &&
29963ef14f0Smrg		    use_scanout(sna, draw, priv)) {
30063ef14f0Smrg			DBG(("%s: requesting scanout compatible back\n", __FUNCTION__));
30163ef14f0Smrg			flags |= CREATE_SCANOUT;
30263ef14f0Smrg		}
30363ef14f0Smrg
30442542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
30542542f5fSchristos				    draw->width, draw->height, draw->bitsPerPixel,
30642542f5fSchristos				    get_private(back)->bo->tiling,
30763ef14f0Smrg				    flags);
30842542f5fSchristos		if (bo == NULL)
30942542f5fSchristos			return;
31042542f5fSchristos
31142542f5fSchristos		name = kgem_bo_flink(&sna->kgem, bo);
31242542f5fSchristos		if (name == 0) {
31342542f5fSchristos			kgem_bo_destroy(&sna->kgem, bo);
31442542f5fSchristos			return;
31542542f5fSchristos		}
31663ef14f0Smrg
31763ef14f0Smrg		flags = 0;
31863ef14f0Smrg		if (USE_ASYNC_SWAP && back->flags) {
31963ef14f0Smrg			BoxRec box;
32063ef14f0Smrg
32163ef14f0Smrg			box.x1 = 0;
32263ef14f0Smrg			box.y1 = 0;
32363ef14f0Smrg			box.x2 = draw->width;
32463ef14f0Smrg			box.y2 = draw->height;
32563ef14f0Smrg
32663ef14f0Smrg			DBG(("%s: filling new buffer with old back\n", __FUNCTION__));
32763ef14f0Smrg			if (sna->render.copy_boxes(sna, GXcopy,
32863ef14f0Smrg						   draw, get_private(back)->bo, 0, 0,
32963ef14f0Smrg						   draw, bo, 0, 0,
33063ef14f0Smrg						   &box, 1, COPY_LAST | COPY_DRI))
33163ef14f0Smrg				flags = back->flags;
33263ef14f0Smrg		}
33342542f5fSchristos	}
33442542f5fSchristos	assert(bo->active_scanout == 0);
33542542f5fSchristos
33663ef14f0Smrg	if (reuse && get_private(back)->bo->refcnt == 1 + get_private(back)->bo->active_scanout) {
33763ef14f0Smrg		if (&c->link == &priv->cache)
33842542f5fSchristos			c = malloc(sizeof(*c));
33942542f5fSchristos		if (c != NULL) {
34042542f5fSchristos			c->bo = ref(get_private(back)->bo);
34142542f5fSchristos			c->name = back->name;
34263ef14f0Smrg			c->flags = back->flags;
34363ef14f0Smrg			list_add(&c->link, &priv->cache);
34463ef14f0Smrg			DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, c->bo->handle, c->name, c->flags, c->bo->active_scanout));
34542542f5fSchristos		}
34663ef14f0Smrg	} else {
34763ef14f0Smrg		if (&c->link != &priv->cache)
34863ef14f0Smrg			free(c);
34942542f5fSchristos	}
35042542f5fSchristos
35163ef14f0Smrg	assert(bo->active_scanout == 0);
35242542f5fSchristos	assert(bo != get_private(back)->bo);
35342542f5fSchristos	kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
35442542f5fSchristos
35542542f5fSchristos	get_private(back)->bo = bo;
35642542f5fSchristos	get_private(back)->size = draw->height << 16 | draw->width;
35742542f5fSchristos	back->pitch = bo->pitch;
35842542f5fSchristos	back->name = name;
35963ef14f0Smrg	back->flags = flags;
36042542f5fSchristos
36163ef14f0Smrg	assert(back->pitch);
36263ef14f0Smrg	assert(back->name);
36342542f5fSchristos
36463ef14f0Smrgout:
36563ef14f0Smrg	get_private(back)->stale = false;
36642542f5fSchristos}
36742542f5fSchristos
36842542f5fSchristosstatic struct sna_dri2_event *
36942542f5fSchristosdri2_chain(DrawablePtr d)
37042542f5fSchristos{
37142542f5fSchristos	struct dri2_window *priv = dri2_window((WindowPtr)d);
37242542f5fSchristos	assert(priv != NULL);
37363ef14f0Smrg	assert(priv->chain == NULL || priv->chain->chained);
37442542f5fSchristos	return priv->chain;
37542542f5fSchristos}
37613496ba1Ssnjinline static DRI2BufferPtr dri2_window_get_front(WindowPtr win)
37713496ba1Ssnj{
37813496ba1Ssnj	struct dri2_window *priv = dri2_window(win);
37963ef14f0Smrg	assert(priv->front == NULL || get_private(priv->front)->bo->active_scanout);
38013496ba1Ssnj	return priv ? priv->front : NULL;
38113496ba1Ssnj}
38242542f5fSchristos#else
38342542f5fSchristosinline static void *dri2_window_get_front(WindowPtr win) { return NULL; }
38463ef14f0Smrg#define APPLY_DAMAGE 1
38542542f5fSchristos#endif
38642542f5fSchristos
38742542f5fSchristos#if DRI2INFOREC_VERSION < 6
38842542f5fSchristos
38913496ba1Ssnj#define xorg_can_triple_buffer() 0
39042542f5fSchristos#define swap_limit(d, l) false
391cbdaa46fSsnj#define mark_stale(b)
39242542f5fSchristos
39342542f5fSchristos#else
39442542f5fSchristos
39542542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,904,0)
39642542f5fSchristos/* Prime fixed for triple buffer support */
39713496ba1Ssnj#define xorg_can_triple_buffer() 1
39842542f5fSchristos#elif XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,12,99,901,0)
39942542f5fSchristos/* Before numGPUScreens was introduced */
40013496ba1Ssnj#define xorg_can_triple_buffer() 1
40142542f5fSchristos#else
40242542f5fSchristos/* Subject to crashers when combining triple buffering and Prime */
40313496ba1Ssnjinline static bool xorg_can_triple_buffer(void)
40442542f5fSchristos{
40542542f5fSchristos	return screenInfo.numGPUScreens == 0;
40642542f5fSchristos}
40742542f5fSchristos#endif
40842542f5fSchristos
40913496ba1Ssnjstatic void
41013496ba1Ssnjmark_stale(DRI2BufferPtr back)
41113496ba1Ssnj{
41213496ba1Ssnj	/* If we have reuse notifications, we can track when the
41313496ba1Ssnj	 * client tries to present an old buffer (one that has not
41413496ba1Ssnj	 * been updated since the last swap) and avoid showing the
41513496ba1Ssnj	 * stale frame. (This is mostly useful for tracking down
41613496ba1Ssnj	 * driver bugs!)
41713496ba1Ssnj	 */
41863ef14f0Smrg	DBG(("%s(handle=%d) => %d\n", __FUNCTION__,
41963ef14f0Smrg	     get_private(back)->bo->handle, xorg_can_triple_buffer()));
42013496ba1Ssnj	get_private(back)->stale = xorg_can_triple_buffer();
42113496ba1Ssnj}
42213496ba1Ssnj
42342542f5fSchristosstatic Bool
42442542f5fSchristossna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
42542542f5fSchristos{
42642542f5fSchristos	DBG(("%s: swap limit set to %d\n", __FUNCTION__, swap_limit));
42742542f5fSchristos	return swap_limit >= 1;
42842542f5fSchristos}
42942542f5fSchristos
43042542f5fSchristosstatic void
43142542f5fSchristossna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
43242542f5fSchristos{
43363ef14f0Smrg	struct sna *sna = to_sna_from_drawable(draw);
43463ef14f0Smrg
43542542f5fSchristos	DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n",
43642542f5fSchristos	     __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
43742542f5fSchristos	     buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
43842542f5fSchristos	assert(get_private(buffer)->refcnt);
43963ef14f0Smrg	assert(get_private(buffer)->bo->refcnt >= get_private(buffer)->bo->active_scanout);
44063ef14f0Smrg	assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
44142542f5fSchristos
44242542f5fSchristos	if (buffer->attachment == DRI2BufferBackLeft &&
44342542f5fSchristos	    draw->type != DRAWABLE_PIXMAP) {
44463ef14f0Smrg		DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id));
44563ef14f0Smrg		sna_dri2_get_back(sna, draw, buffer);
44642542f5fSchristos
44742542f5fSchristos		assert(get_private(buffer)->bo->refcnt);
44842542f5fSchristos		assert(get_private(buffer)->bo->active_scanout == 0);
44963ef14f0Smrg		assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
45063ef14f0Smrg		DBG(("%s: reusing back buffer handle=%d, name=%d, pitch=%d, age=%d\n",
45163ef14f0Smrg		     __FUNCTION__, get_private(buffer)->bo->handle,
45263ef14f0Smrg		     buffer->name, buffer->pitch, buffer->flags));
45342542f5fSchristos	}
45463ef14f0Smrg
45563ef14f0Smrg	kgem_bo_submit(&sna->kgem, get_private(buffer)->bo);
45642542f5fSchristos}
45742542f5fSchristos
45842542f5fSchristosstatic bool swap_limit(DrawablePtr draw, int limit)
45942542f5fSchristos{
46013496ba1Ssnj	if (!xorg_can_triple_buffer())
46113496ba1Ssnj		return false;
46213496ba1Ssnj
46342542f5fSchristos	DBG(("%s: draw=%ld setting swap limit to %d\n", __FUNCTION__, (long)draw->id, limit));
46442542f5fSchristos	DRI2SwapLimit(draw, limit);
46542542f5fSchristos	return true;
46642542f5fSchristos}
46742542f5fSchristos#endif
46842542f5fSchristos
46942542f5fSchristos#define COLOR_PREFER_TILING_Y 0
47042542f5fSchristos
47142542f5fSchristos/* Prefer to enable TILING_Y if this buffer will never be a
47242542f5fSchristos * candidate for pageflipping
47342542f5fSchristos */
47442542f5fSchristosstatic uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
47542542f5fSchristos{
47642542f5fSchristos	uint32_t tiling;
47742542f5fSchristos
47863ef14f0Smrg	if (!sna->kgem.can_fence)
47963ef14f0Smrg		return I915_TILING_NONE;
48063ef14f0Smrg
48142542f5fSchristos	if (COLOR_PREFER_TILING_Y &&
48242542f5fSchristos	    (draw->width  != sna->front->drawable.width ||
48342542f5fSchristos	     draw->height != sna->front->drawable.height))
48442542f5fSchristos		tiling = I915_TILING_Y;
48542542f5fSchristos	else
48642542f5fSchristos		tiling = I915_TILING_X;
48742542f5fSchristos
48842542f5fSchristos	return kgem_choose_tiling(&sna->kgem, -tiling,
48942542f5fSchristos				  draw->width,
49042542f5fSchristos				  draw->height,
49142542f5fSchristos				  draw->bitsPerPixel);
49242542f5fSchristos}
49342542f5fSchristos
49442542f5fSchristosstatic uint32_t other_tiling(struct sna *sna, DrawablePtr draw)
49542542f5fSchristos{
49642542f5fSchristos	/* XXX Can mix color X / depth Y? */
49742542f5fSchristos	return kgem_choose_tiling(&sna->kgem,
49842542f5fSchristos				  sna->kgem.gen >= 040 ? -I915_TILING_Y : -I915_TILING_X,
49942542f5fSchristos				  draw->width,
50042542f5fSchristos				  draw->height,
50142542f5fSchristos				  draw->bitsPerPixel);
50242542f5fSchristos}
50342542f5fSchristos
50442542f5fSchristosstatic struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
50542542f5fSchristos					  PixmapPtr pixmap)
50642542f5fSchristos{
50742542f5fSchristos	struct sna_pixmap *priv;
50842542f5fSchristos
50942542f5fSchristos	DBG(("%s: attaching DRI client to pixmap=%ld\n",
51042542f5fSchristos	     __FUNCTION__, pixmap->drawable.serialNumber));
51142542f5fSchristos
51242542f5fSchristos	priv = sna_pixmap(pixmap);
51342542f5fSchristos	if (priv != NULL && IS_STATIC_PTR(priv->ptr) && priv->cpu_bo) {
51442542f5fSchristos		DBG(("%s: SHM or unattached Pixmap, BadAlloc\n", __FUNCTION__));
51542542f5fSchristos		return NULL;
51642542f5fSchristos	}
51742542f5fSchristos
51842542f5fSchristos	priv = sna_pixmap_move_to_gpu(pixmap,
51942542f5fSchristos				      MOVE_READ | __MOVE_FORCE | __MOVE_DRI);
52042542f5fSchristos	if (priv == NULL) {
52142542f5fSchristos		DBG(("%s: failed to move to GPU, BadAlloc\n", __FUNCTION__));
52242542f5fSchristos		return NULL;
52342542f5fSchristos	}
52442542f5fSchristos
52563ef14f0Smrg	assert(priv->flush == false || priv->pinned & PIN_DRI3);
52663ef14f0Smrg	assert(priv->gpu_bo->flush == false || priv->pinned & PIN_DRI3);
52742542f5fSchristos	assert(priv->cpu_damage == NULL);
52842542f5fSchristos	assert(priv->gpu_bo);
52942542f5fSchristos	assert(priv->gpu_bo->proxy == NULL);
53042542f5fSchristos
53163ef14f0Smrg	if (!kgem_bo_is_fenced(&sna->kgem, priv->gpu_bo)) {
53263ef14f0Smrg		if (priv->gpu_bo->tiling &&
53363ef14f0Smrg		    !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
53463ef14f0Smrg			DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling));
53563ef14f0Smrg			return NULL;
53663ef14f0Smrg		}
53763ef14f0Smrg	} else {
53863ef14f0Smrg		int tiling = color_tiling(sna, &pixmap->drawable);
53963ef14f0Smrg		if (tiling < 0)
54063ef14f0Smrg			tiling = -tiling;
54163ef14f0Smrg		if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout)
54263ef14f0Smrg			sna_pixmap_change_tiling(pixmap, tiling);
54363ef14f0Smrg	}
54442542f5fSchristos
54563ef14f0Smrg	priv->gpu_bo->active_scanout++;
54642542f5fSchristos
54763ef14f0Smrg	return priv->gpu_bo;
54842542f5fSchristos}
54942542f5fSchristos
55042542f5fSchristosvoid
55142542f5fSchristossna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
55242542f5fSchristos{
55342542f5fSchristos	DRI2BufferPtr buffer;
55442542f5fSchristos	struct sna_dri2_private *private;
55542542f5fSchristos
55642542f5fSchristos	buffer = sna_pixmap_get_buffer(pixmap);
55742542f5fSchristos	if (buffer == NULL)
55842542f5fSchristos		return;
55942542f5fSchristos
56042542f5fSchristos	DBG(("%s: pixmap=%ld, old handle=%d, new handle=%d\n", __FUNCTION__,
56142542f5fSchristos	     pixmap->drawable.serialNumber,
56242542f5fSchristos	     get_private(buffer)->bo->handle,
56342542f5fSchristos	     sna_pixmap(pixmap)->gpu_bo->handle));
56442542f5fSchristos
56542542f5fSchristos	private = get_private(buffer);
56642542f5fSchristos	assert(private->pixmap == pixmap);
56742542f5fSchristos
56842542f5fSchristos	assert(bo != private->bo);
56942542f5fSchristos	if (private->bo == bo)
57042542f5fSchristos		return;
57142542f5fSchristos
57263ef14f0Smrg	assert(private->bo->active_scanout > 0);
57363ef14f0Smrg	private->bo->active_scanout--;
57463ef14f0Smrg
57542542f5fSchristos	DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
57642542f5fSchristos	private->bo->flush = false;
57742542f5fSchristos	kgem_bo_destroy(&sna->kgem, private->bo);
57842542f5fSchristos
57963ef14f0Smrg
58042542f5fSchristos	buffer->name = kgem_bo_flink(&sna->kgem, bo);
58113496ba1Ssnj	buffer->pitch = bo->pitch;
58242542f5fSchristos	private->bo = ref(bo);
58363ef14f0Smrg	bo->active_scanout++;
58442542f5fSchristos
58542542f5fSchristos	DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
58642542f5fSchristos	bo->flush = true;
58713496ba1Ssnj	if (bo->exec)
58813496ba1Ssnj		sna->kgem.flush = 1;
58942542f5fSchristos	assert(sna_pixmap(pixmap)->flush);
59042542f5fSchristos
59142542f5fSchristos	/* XXX DRI2InvalidateDrawable(&pixmap->drawable); */
59242542f5fSchristos}
59342542f5fSchristos
59442542f5fSchristosstatic DRI2Buffer2Ptr
59542542f5fSchristossna_dri2_create_buffer(DrawablePtr draw,
59642542f5fSchristos		       unsigned int attachment,
59742542f5fSchristos		       unsigned int format)
59842542f5fSchristos{
59942542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
60042542f5fSchristos	DRI2Buffer2Ptr buffer;
60142542f5fSchristos	struct sna_dri2_private *private;
60242542f5fSchristos	PixmapPtr pixmap;
60342542f5fSchristos	struct kgem_bo *bo;
60463ef14f0Smrg	unsigned bpp = format ?: draw->bitsPerPixel;
60563ef14f0Smrg	unsigned flags = CREATE_EXACT;
60642542f5fSchristos	uint32_t size;
60742542f5fSchristos
60813496ba1Ssnj	DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n",
60942542f5fSchristos	     __FUNCTION__,
61042542f5fSchristos	     get_drawable_pixmap(draw)->drawable.serialNumber,
61113496ba1Ssnj	     attachment, format, draw->width, draw->height,
61213496ba1Ssnj	     draw->type != DRAWABLE_PIXMAP));
61342542f5fSchristos
61442542f5fSchristos	pixmap = NULL;
61542542f5fSchristos	size = (uint32_t)draw->height << 16 | draw->width;
61642542f5fSchristos	switch (attachment) {
61742542f5fSchristos	case DRI2BufferFrontLeft:
61863ef14f0Smrg		sna->needs_dri_flush = true;
61963ef14f0Smrg
62042542f5fSchristos		pixmap = get_drawable_pixmap(draw);
62142542f5fSchristos		buffer = NULL;
62242542f5fSchristos		if (draw->type != DRAWABLE_PIXMAP)
62342542f5fSchristos			buffer = dri2_window_get_front((WindowPtr)draw);
62442542f5fSchristos		if (buffer == NULL)
62563ef14f0Smrg			buffer = (DRI2Buffer2Ptr)sna_pixmap_get_buffer(pixmap);
62642542f5fSchristos		if (buffer) {
62742542f5fSchristos			private = get_private(buffer);
62842542f5fSchristos
62963ef14f0Smrg			DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d, active_scanout=%d\n",
63042542f5fSchristos			     __FUNCTION__,
63142542f5fSchristos			     draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
63242542f5fSchristos			     draw->width, draw->height,
63342542f5fSchristos			     pixmap->drawable.serialNumber,
63413496ba1Ssnj			     private->pixmap->drawable.serialNumber,
63542542f5fSchristos			     pixmap->drawable.width,
63642542f5fSchristos			     pixmap->drawable.height,
63763ef14f0Smrg			     private->bo->handle, buffer->name,
63863ef14f0Smrg			     private->bo->active_scanout));
63942542f5fSchristos
64063ef14f0Smrg			assert(buffer->attachment == DRI2BufferFrontLeft);
64142542f5fSchristos			assert(private->pixmap == pixmap);
64242542f5fSchristos			assert(sna_pixmap(pixmap)->flush);
64342542f5fSchristos			assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
64442542f5fSchristos			assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
64563ef14f0Smrg			assert(private->bo->pitch == buffer->pitch);
64663ef14f0Smrg			assert(private->bo->active_scanout);
64742542f5fSchristos
64842542f5fSchristos			private->refcnt++;
64942542f5fSchristos			return buffer;
65042542f5fSchristos		}
65142542f5fSchristos
65242542f5fSchristos		bo = sna_pixmap_set_dri(sna, pixmap);
65342542f5fSchristos		if (bo == NULL)
65442542f5fSchristos			return NULL;
65542542f5fSchristos
65642542f5fSchristos		assert(sna_pixmap(pixmap) != NULL);
65742542f5fSchristos
65842542f5fSchristos		bo = ref(bo);
65942542f5fSchristos		if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB))
66042542f5fSchristos			flags |= CREATE_SCANOUT;
66142542f5fSchristos		DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n",
66242542f5fSchristos		     __FUNCTION__,
66342542f5fSchristos		     pixmap->drawable.width, pixmap->drawable.height,
66442542f5fSchristos		     pixmap, pixmap->refcnt, flags & CREATE_SCANOUT));
66542542f5fSchristos		size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width;
66663ef14f0Smrg		bpp = pixmap->drawable.bitsPerPixel;
66742542f5fSchristos		break;
66842542f5fSchristos
66942542f5fSchristos	case DRI2BufferBackLeft:
67042542f5fSchristos		if (draw->type != DRAWABLE_PIXMAP) {
67142542f5fSchristos			if (dri2_window_get_front((WindowPtr)draw))
67242542f5fSchristos				flags |= CREATE_SCANOUT;
67342542f5fSchristos			if (draw->width  == sna->front->drawable.width &&
67442542f5fSchristos			    draw->height == sna->front->drawable.height &&
67563ef14f0Smrg			    draw->bitsPerPixel == bpp &&
67642542f5fSchristos			    (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
67742542f5fSchristos				flags |= CREATE_SCANOUT;
67842542f5fSchristos		}
67942542f5fSchristos	case DRI2BufferBackRight:
68042542f5fSchristos	case DRI2BufferFrontRight:
68142542f5fSchristos	case DRI2BufferFakeFrontLeft:
68242542f5fSchristos	case DRI2BufferFakeFrontRight:
68342542f5fSchristos		DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n",
68442542f5fSchristos		     __FUNCTION__,
68542542f5fSchristos		     draw->width, draw->height,
68642542f5fSchristos		     flags & CREATE_SCANOUT));
68742542f5fSchristos
68842542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
68942542f5fSchristos				    draw->width,
69042542f5fSchristos				    draw->height,
69163ef14f0Smrg				    bpp,
69242542f5fSchristos				    color_tiling(sna, draw),
69342542f5fSchristos				    flags);
69442542f5fSchristos		break;
69542542f5fSchristos
69642542f5fSchristos	case DRI2BufferStencil:
69742542f5fSchristos		/*
69842542f5fSchristos		 * The stencil buffer has quirky pitch requirements.  From Vol
69942542f5fSchristos		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
70042542f5fSchristos		 * Pitch":
70142542f5fSchristos		 *    The pitch must be set to 2x the value computed based on
70242542f5fSchristos		 *    width, as the stencil buffer is stored with two rows
70342542f5fSchristos		 *    interleaved.
70442542f5fSchristos		 * To accomplish this, we resort to the nasty hack of doubling
70542542f5fSchristos		 * the drm region's cpp and halving its height.
70642542f5fSchristos		 *
70742542f5fSchristos		 * If we neglect to double the pitch, then
70842542f5fSchristos		 * drm_intel_gem_bo_map_gtt() maps the memory incorrectly.
70942542f5fSchristos		 *
71042542f5fSchristos		 * The alignment for W-tiling is quite different to the
71142542f5fSchristos		 * nominal no-tiling case, so we have to account for
71242542f5fSchristos		 * the tiled access pattern explicitly.
71342542f5fSchristos		 *
71442542f5fSchristos		 * The stencil buffer is W tiled. However, we request from
71542542f5fSchristos		 * the kernel a non-tiled buffer because the kernel does
71642542f5fSchristos		 * not understand W tiling and the GTT is incapable of
71742542f5fSchristos		 * W fencing.
71842542f5fSchristos		 */
71942542f5fSchristos		bpp *= 2;
72042542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
72142542f5fSchristos				    ALIGN(draw->width, 64),
72242542f5fSchristos				    ALIGN((draw->height + 1) / 2, 64),
72342542f5fSchristos				    bpp, I915_TILING_NONE, flags);
72442542f5fSchristos		break;
72542542f5fSchristos
72642542f5fSchristos	case DRI2BufferDepth:
72742542f5fSchristos	case DRI2BufferDepthStencil:
72842542f5fSchristos	case DRI2BufferHiz:
72942542f5fSchristos	case DRI2BufferAccum:
73042542f5fSchristos		bo = kgem_create_2d(&sna->kgem,
73142542f5fSchristos				    draw->width, draw->height, bpp,
73242542f5fSchristos				    other_tiling(sna, draw),
73342542f5fSchristos				    flags);
73442542f5fSchristos		break;
73542542f5fSchristos
73642542f5fSchristos	default:
73742542f5fSchristos		return NULL;
73842542f5fSchristos	}
73942542f5fSchristos	if (bo == NULL)
74042542f5fSchristos		return NULL;
74142542f5fSchristos
74242542f5fSchristos	buffer = calloc(1, sizeof *buffer + sizeof *private);
74342542f5fSchristos	if (buffer == NULL)
74442542f5fSchristos		goto err;
74542542f5fSchristos
74642542f5fSchristos	private = get_private(buffer);
74742542f5fSchristos	buffer->attachment = attachment;
74842542f5fSchristos	buffer->pitch = bo->pitch;
74942542f5fSchristos	buffer->cpp = bpp / 8;
75042542f5fSchristos	buffer->driverPrivate = private;
75142542f5fSchristos	buffer->format = format;
75242542f5fSchristos	buffer->flags = 0;
75342542f5fSchristos	buffer->name = kgem_bo_flink(&sna->kgem, bo);
75442542f5fSchristos	private->refcnt = 1;
75542542f5fSchristos	private->bo = bo;
75642542f5fSchristos	private->pixmap = pixmap;
75742542f5fSchristos	private->size = size;
75842542f5fSchristos
75942542f5fSchristos	if (buffer->name == 0)
76042542f5fSchristos		goto err;
76142542f5fSchristos
76242542f5fSchristos	if (pixmap) {
76342542f5fSchristos		struct sna_pixmap *priv;
76442542f5fSchristos
76542542f5fSchristos		assert(attachment == DRI2BufferFrontLeft);
76642542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == NULL);
76742542f5fSchristos
76842542f5fSchristos		sna_pixmap_set_buffer(pixmap, buffer);
76942542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == buffer);
77042542f5fSchristos		pixmap->refcnt++;
77142542f5fSchristos
77242542f5fSchristos		priv = sna_pixmap(pixmap);
77363ef14f0Smrg		assert(priv->flush == false || priv->pinned & PIN_DRI3);
77442542f5fSchristos		assert((priv->pinned & PIN_DRI2) == 0);
77542542f5fSchristos
77642542f5fSchristos		/* Don't allow this named buffer to be replaced */
77742542f5fSchristos		priv->pinned |= PIN_DRI2;
77842542f5fSchristos
77942542f5fSchristos		/* We need to submit any modifications to and reads from this
78042542f5fSchristos		 * buffer before we send any reply to the Client.
78142542f5fSchristos		 *
78242542f5fSchristos		 * As we don't track which Client, we flush for all.
78342542f5fSchristos		 */
78442542f5fSchristos		DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
78542542f5fSchristos		priv->gpu_bo->flush = true;
78642542f5fSchristos		if (priv->gpu_bo->exec)
78742542f5fSchristos			sna->kgem.flush = 1;
78842542f5fSchristos
78963ef14f0Smrg		priv->flush |= FLUSH_READ;
79042542f5fSchristos		if (draw->type == DRAWABLE_PIXMAP) {
79142542f5fSchristos			/* DRI2 renders directly into GLXPixmaps, treat as hostile */
79242542f5fSchristos			kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
79342542f5fSchristos			sna_damage_all(&priv->gpu_damage, pixmap);
79442542f5fSchristos			priv->clear = false;
79542542f5fSchristos			priv->cpu = false;
79663ef14f0Smrg			priv->flush |= FLUSH_WRITE;
79742542f5fSchristos		}
79842542f5fSchristos
79963ef14f0Smrg		sna_watch_flush(sna, 1);
80042542f5fSchristos	}
80142542f5fSchristos
80242542f5fSchristos	return buffer;
80342542f5fSchristos
80442542f5fSchristoserr:
80542542f5fSchristos	kgem_bo_destroy(&sna->kgem, bo);
80642542f5fSchristos	free(buffer);
80742542f5fSchristos	return NULL;
80842542f5fSchristos}
80942542f5fSchristos
81063ef14f0Smrgstatic void
81163ef14f0Smrgsna_dri2_cache_bo(struct sna *sna,
81263ef14f0Smrg		  DrawablePtr draw,
81363ef14f0Smrg		  struct kgem_bo *bo,
81463ef14f0Smrg		  uint32_t name,
81563ef14f0Smrg		  uint32_t size,
81663ef14f0Smrg		  uint32_t flags)
81763ef14f0Smrg{
81863ef14f0Smrg	struct dri_bo *c;
81963ef14f0Smrg
82063ef14f0Smrg	DBG(("%s(handle=%d, name=%d)\n", __FUNCTION__, bo->handle, name));
82163ef14f0Smrg
82263ef14f0Smrg	if (draw == NULL) {
82363ef14f0Smrg		DBG(("%s: no draw, releasing handle=%d\n",
82463ef14f0Smrg		     __FUNCTION__, bo->handle));
82563ef14f0Smrg		goto err;
82663ef14f0Smrg	}
82763ef14f0Smrg
82863ef14f0Smrg	if (draw->type == DRAWABLE_PIXMAP) {
82963ef14f0Smrg		DBG(("%s: not a window, releasing handle=%d\n",
83063ef14f0Smrg		     __FUNCTION__, bo->handle));
83163ef14f0Smrg		goto err;
83263ef14f0Smrg	}
83363ef14f0Smrg
83463ef14f0Smrg	if (bo->refcnt > 1 + bo->active_scanout) {
83563ef14f0Smrg		DBG(("%s: multiple references [%d], releasing handle\n",
83663ef14f0Smrg		     __FUNCTION__, bo->refcnt, bo->handle));
83763ef14f0Smrg		goto err;
83863ef14f0Smrg	}
83963ef14f0Smrg
84063ef14f0Smrg	if ((draw->height << 16 | draw->width) != size) {
84163ef14f0Smrg		DBG(("%s: wrong size [%dx%d], releasing handle\n",
84263ef14f0Smrg		     __FUNCTION__,
84363ef14f0Smrg		     size & 0xffff, size >> 16,
84463ef14f0Smrg		     bo->handle));
84563ef14f0Smrg		goto err;
84663ef14f0Smrg	}
84763ef14f0Smrg
84863ef14f0Smrg	if (bo->scanout && front_pitch(draw) != bo->pitch) {
84963ef14f0Smrg		DBG(("%s: scanout with pitch change [%d != %d], releasing handle\n",
85063ef14f0Smrg		     __FUNCTION__, bo->pitch, front_pitch(draw), bo->handle));
85163ef14f0Smrg		goto err;
85263ef14f0Smrg	}
85363ef14f0Smrg
85463ef14f0Smrg	c = malloc(sizeof(*c));
85563ef14f0Smrg	if (!c)
85663ef14f0Smrg		goto err;
85763ef14f0Smrg
85863ef14f0Smrg	DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, bo->handle, name, flags, bo->active_scanout));
85963ef14f0Smrg
86063ef14f0Smrg	c->bo = bo;
86163ef14f0Smrg	c->name = name;
86263ef14f0Smrg	c->flags = flags;
86363ef14f0Smrg	list_add(&c->link, &dri2_window((WindowPtr)draw)->cache);
86463ef14f0Smrg	return;
86563ef14f0Smrg
86663ef14f0Smrgerr:
86763ef14f0Smrg	kgem_bo_destroy(&sna->kgem, bo);
86863ef14f0Smrg}
86963ef14f0Smrg
87063ef14f0Smrgstatic void _sna_dri2_destroy_buffer(struct sna *sna,
87163ef14f0Smrg				     DrawablePtr draw,
87263ef14f0Smrg				     DRI2Buffer2Ptr buffer)
87342542f5fSchristos{
87442542f5fSchristos	struct sna_dri2_private *private = get_private(buffer);
87542542f5fSchristos
87642542f5fSchristos	if (buffer == NULL)
87742542f5fSchristos		return;
87842542f5fSchristos
87963ef14f0Smrg	DBG(("%s: %p [handle=%d] -- refcnt=%d, draw=%ld, pixmap=%ld, proxy?=%d\n",
88042542f5fSchristos	     __FUNCTION__, buffer, private->bo->handle, private->refcnt,
88163ef14f0Smrg	     draw ? draw->id : 0,
88263ef14f0Smrg	     private->pixmap ? private->pixmap->drawable.serialNumber : 0,
88363ef14f0Smrg	     private->proxy != NULL));
88442542f5fSchristos	assert(private->refcnt > 0);
88542542f5fSchristos	if (--private->refcnt)
88642542f5fSchristos		return;
88742542f5fSchristos
88842542f5fSchristos	assert(private->bo);
88942542f5fSchristos
89042542f5fSchristos	if (private->proxy) {
89142542f5fSchristos		DBG(("%s: destroying proxy\n", __FUNCTION__));
89263ef14f0Smrg		assert(private->bo->active_scanout > 0);
89363ef14f0Smrg		private->bo->active_scanout--;
89463ef14f0Smrg
89563ef14f0Smrg		_sna_dri2_destroy_buffer(sna, draw, private->proxy);
89642542f5fSchristos		private->pixmap = NULL;
89742542f5fSchristos	}
89842542f5fSchristos
89942542f5fSchristos	if (private->pixmap) {
90042542f5fSchristos		PixmapPtr pixmap = private->pixmap;
90142542f5fSchristos		struct sna_pixmap *priv = sna_pixmap(pixmap);
90242542f5fSchristos
90342542f5fSchristos		assert(sna_pixmap_get_buffer(pixmap) == buffer);
90442542f5fSchristos		assert(priv->gpu_bo == private->bo);
90542542f5fSchristos		assert(priv->gpu_bo->flush);
90642542f5fSchristos		assert(priv->pinned & PIN_DRI2);
90742542f5fSchristos		assert(priv->flush);
90842542f5fSchristos
90963ef14f0Smrg		DBG(("%s: removing active_scanout=%d from pixmap handle=%d\n",
91063ef14f0Smrg		     __FUNCTION__, priv->gpu_bo->active_scanout, priv->gpu_bo->handle));
91163ef14f0Smrg		assert(priv->gpu_bo->active_scanout > 0);
91263ef14f0Smrg		priv->gpu_bo->active_scanout--;
91363ef14f0Smrg
91442542f5fSchristos		/* Undo the DRI markings on this pixmap */
91542542f5fSchristos		DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n",
91642542f5fSchristos		     __FUNCTION__,
91742542f5fSchristos		     pixmap->drawable.serialNumber,
91842542f5fSchristos		     pixmap == sna->front));
91942542f5fSchristos
92042542f5fSchristos		list_del(&priv->flush_list);
92142542f5fSchristos
92242542f5fSchristos		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
92342542f5fSchristos		priv->pinned &= ~PIN_DRI2;
92442542f5fSchristos
92563ef14f0Smrg		if ((priv->pinned & PIN_DRI3) == 0) {
92663ef14f0Smrg			priv->gpu_bo->flush = false;
92763ef14f0Smrg			priv->flush = false;
92863ef14f0Smrg		}
92963ef14f0Smrg		sna_watch_flush(sna, -1);
93042542f5fSchristos
93142542f5fSchristos		sna_pixmap_set_buffer(pixmap, NULL);
93242542f5fSchristos		pixmap->drawable.pScreen->DestroyPixmap(pixmap);
93342542f5fSchristos	}
93442542f5fSchristos
93563ef14f0Smrg	sna_dri2_cache_bo(sna, draw,
93663ef14f0Smrg			  private->bo,
93763ef14f0Smrg			  buffer->name,
93863ef14f0Smrg			  private->size,
93963ef14f0Smrg			  buffer->flags);
94042542f5fSchristos	free(buffer);
94142542f5fSchristos}
94242542f5fSchristos
94342542f5fSchristosstatic void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
94442542f5fSchristos{
94563ef14f0Smrg	_sna_dri2_destroy_buffer(to_sna_from_drawable(draw), draw, buffer);
94642542f5fSchristos}
94742542f5fSchristos
94842542f5fSchristosstatic DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer)
94942542f5fSchristos{
95063ef14f0Smrg	assert(get_private(buffer)->refcnt > 0);
95142542f5fSchristos	get_private(buffer)->refcnt++;
95242542f5fSchristos	return buffer;
95342542f5fSchristos}
95442542f5fSchristos
95542542f5fSchristosstatic inline void damage(PixmapPtr pixmap, struct sna_pixmap *priv, RegionPtr region)
95642542f5fSchristos{
95742542f5fSchristos	assert(priv->gpu_bo);
95842542f5fSchristos	if (DAMAGE_IS_ALL(priv->gpu_damage))
95942542f5fSchristos		goto done;
96042542f5fSchristos
96142542f5fSchristos	if (region == NULL) {
96242542f5fSchristosdamage_all:
96342542f5fSchristos		priv->gpu_damage = _sna_damage_all(priv->gpu_damage,
96442542f5fSchristos						   pixmap->drawable.width,
96542542f5fSchristos						   pixmap->drawable.height);
96642542f5fSchristos		sna_damage_destroy(&priv->cpu_damage);
96742542f5fSchristos		list_del(&priv->flush_list);
96842542f5fSchristos	} else {
96942542f5fSchristos		sna_damage_subtract(&priv->cpu_damage, region);
97042542f5fSchristos		if (priv->cpu_damage == NULL)
97142542f5fSchristos			goto damage_all;
97242542f5fSchristos		sna_damage_add(&priv->gpu_damage, region);
97342542f5fSchristos	}
97442542f5fSchristosdone:
97542542f5fSchristos	priv->cpu = false;
97642542f5fSchristos	priv->clear = false;
97742542f5fSchristos}
97842542f5fSchristos
97942542f5fSchristosstatic void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
98042542f5fSchristos{
98142542f5fSchristos	struct sna *sna = to_sna_from_pixmap(pixmap);
98242542f5fSchristos	struct sna_pixmap *priv = sna_pixmap(pixmap);
98342542f5fSchristos
98463ef14f0Smrg	DBG(("%s: pixmap=%ld, handle=%d (old handle=%d)\n",
98563ef14f0Smrg	     __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, priv->gpu_bo->handle));
98642542f5fSchristos
98742542f5fSchristos	assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
98842542f5fSchristos	assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
98942542f5fSchristos	assert(bo->proxy == NULL);
99042542f5fSchristos	assert(priv->pinned & PIN_DRI2);
99142542f5fSchristos	assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
99242542f5fSchristos	assert(priv->flush);
99342542f5fSchristos
99463ef14f0Smrg	if (APPLY_DAMAGE) {
99563ef14f0Smrg		RegionRec region;
99663ef14f0Smrg
99763ef14f0Smrg		/* Post damage on the new front buffer so that listeners, such
99863ef14f0Smrg		 * as DisplayLink know take a copy and shove it over the USB,
99963ef14f0Smrg		 * also for software cursors and the like.
100063ef14f0Smrg		 */
100163ef14f0Smrg		region.extents.x1 = region.extents.y1 = 0;
100263ef14f0Smrg		region.extents.x2 = pixmap->drawable.width;
100363ef14f0Smrg		region.extents.y2 = pixmap->drawable.height;
100463ef14f0Smrg		region.data = NULL;
100563ef14f0Smrg
100663ef14f0Smrg		/*
100763ef14f0Smrg		 * Eeek, beware the sw cursor copying to the old bo
100863ef14f0Smrg		 * causing recursion and mayhem.
100963ef14f0Smrg		 */
101063ef14f0Smrg		DBG(("%s: marking whole pixmap as damaged\n", __FUNCTION__));
101163ef14f0Smrg		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
101263ef14f0Smrg		DamageRegionAppend(&pixmap->drawable, &region);
101363ef14f0Smrg	}
101442542f5fSchristos
101542542f5fSchristos	damage(pixmap, priv, NULL);
101642542f5fSchristos
101742542f5fSchristos	assert(bo->refcnt);
101863ef14f0Smrg	if (priv->move_to_gpu) {
101963ef14f0Smrg		DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__));
102042542f5fSchristos		priv->move_to_gpu(sna, priv, 0);
102163ef14f0Smrg	}
102242542f5fSchristos	if (priv->gpu_bo != bo) {
102342542f5fSchristos		DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
102442542f5fSchristos		priv->gpu_bo->flush = false;
102542542f5fSchristos		if (priv->cow)
102642542f5fSchristos			sna_pixmap_undo_cow(sna, priv, 0);
102742542f5fSchristos		if (priv->gpu_bo) {
102842542f5fSchristos			sna_pixmap_unmap(pixmap, priv);
102942542f5fSchristos			kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
103042542f5fSchristos		}
103142542f5fSchristos		DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
103242542f5fSchristos		bo->flush = true;
103342542f5fSchristos		if (bo->exec)
103442542f5fSchristos			sna->kgem.flush = 1;
103542542f5fSchristos		priv->gpu_bo = ref(bo);
103642542f5fSchristos	}
103742542f5fSchristos	if (bo->domain != DOMAIN_GPU)
103842542f5fSchristos		bo->domain = DOMAIN_NONE;
103942542f5fSchristos	assert(bo->flush);
104042542f5fSchristos
104163ef14f0Smrg	if (APPLY_DAMAGE) {
104263ef14f0Smrg		sna->ignore_copy_area = false;
104363ef14f0Smrg		DamageRegionProcessPending(&pixmap->drawable);
104463ef14f0Smrg	}
104563ef14f0Smrg}
104663ef14f0Smrg
104763ef14f0Smrg#if defined(__GNUC__)
104863ef14f0Smrg#define popcount(x) __builtin_popcount(x)
104963ef14f0Smrg#else
105063ef14f0Smrgstatic int popcount(unsigned int x)
105163ef14f0Smrg{
105263ef14f0Smrg	int count = 0;
105363ef14f0Smrg
105463ef14f0Smrg	while (x) {
105563ef14f0Smrg		count += x&1;
105663ef14f0Smrg		x >>= 1;
105763ef14f0Smrg	}
105863ef14f0Smrg
105963ef14f0Smrg	return count;
106042542f5fSchristos}
106163ef14f0Smrg#endif
106242542f5fSchristos
106342542f5fSchristosstatic void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync)
106442542f5fSchristos{
106542542f5fSchristos	struct drm_i915_gem_busy busy;
106642542f5fSchristos	int mode;
106742542f5fSchristos
106842542f5fSchristos	if (sna->kgem.gen < 060)
106942542f5fSchristos		return;
107042542f5fSchristos
107142542f5fSchristos	if (sync) {
107242542f5fSchristos		DBG(("%s: sync, force %s ring\n", __FUNCTION__,
107342542f5fSchristos		     sna->kgem.gen >= 070 ? "BLT" : "RENDER"));
107442542f5fSchristos		kgem_set_mode(&sna->kgem,
107542542f5fSchristos			      sna->kgem.gen >= 070 ? KGEM_BLT : KGEM_RENDER,
107642542f5fSchristos			      dst);
107742542f5fSchristos		return;
107842542f5fSchristos	}
107942542f5fSchristos
108042542f5fSchristos	if (DBG_FORCE_COPY != -1) {
108142542f5fSchristos		DBG(("%s: forcing %d\n", __FUNCTION__, DBG_FORCE_COPY));
108242542f5fSchristos		kgem_set_mode(&sna->kgem, DBG_FORCE_COPY, dst);
108342542f5fSchristos		return;
108442542f5fSchristos	}
108542542f5fSchristos
108642542f5fSchristos	if (sna->kgem.mode != KGEM_NONE) {
108742542f5fSchristos		DBG(("%s: busy, not switching\n", __FUNCTION__));
108842542f5fSchristos		return;
108942542f5fSchristos	}
109042542f5fSchristos
109163ef14f0Smrg	if (sna->render_state.gt < 2 && sna->kgem.has_semaphores) {
109263ef14f0Smrg		DBG(("%s: small GT [%d], not forcing selection\n",
109363ef14f0Smrg		     __FUNCTION__, sna->render_state.gt));
109463ef14f0Smrg		return;
109563ef14f0Smrg	}
109663ef14f0Smrg
109742542f5fSchristos	VG_CLEAR(busy);
109842542f5fSchristos	busy.handle = src->handle;
109942542f5fSchristos	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
110042542f5fSchristos		return;
110142542f5fSchristos
110242542f5fSchristos	DBG(("%s: src handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy));
110342542f5fSchristos	if (busy.busy == 0) {
110442542f5fSchristos		__kgem_bo_clear_busy(src);
110542542f5fSchristos
110642542f5fSchristos		busy.handle = dst->handle;
110742542f5fSchristos		if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
110842542f5fSchristos			return;
110942542f5fSchristos
111042542f5fSchristos		DBG(("%s: dst handle=%d busy?=%x\n", __FUNCTION__, busy.handle, busy.busy));
111142542f5fSchristos		if (busy.busy == 0) {
111242542f5fSchristos			__kgem_bo_clear_busy(dst);
111342542f5fSchristos			DBG(("%s: src/dst is idle, using defaults\n", __FUNCTION__));
111442542f5fSchristos			return;
111542542f5fSchristos		}
111642542f5fSchristos	}
111742542f5fSchristos
111842542f5fSchristos	/* Sandybridge introduced a separate ring which it uses to
111942542f5fSchristos	 * perform blits. Switching rendering between rings incurs
112042542f5fSchristos	 * a stall as we wait upon the old ring to finish and
112142542f5fSchristos	 * flush its render cache before we can proceed on with
112242542f5fSchristos	 * the operation on the new ring.
112342542f5fSchristos	 *
112442542f5fSchristos	 * As this buffer, we presume, has just been written to by
112542542f5fSchristos	 * the DRI client using the RENDER ring, we want to perform
112642542f5fSchristos	 * our operation on the same ring, and ideally on the same
112742542f5fSchristos	 * ring as we will flip from (which should be the RENDER ring
112842542f5fSchristos	 * as well).
112942542f5fSchristos	 *
113042542f5fSchristos	 * The ultimate question is whether preserving the ring outweighs
113142542f5fSchristos	 * the cost of the query.
113242542f5fSchristos	 */
113342542f5fSchristos	mode = KGEM_RENDER;
113463ef14f0Smrg	if ((busy.busy & 0xffff) == I915_EXEC_BLT)
113542542f5fSchristos		mode = KGEM_BLT;
113663ef14f0Smrg	kgem_bo_mark_busy(&sna->kgem,
113763ef14f0Smrg			  busy.handle == src->handle ? src : dst,
113863ef14f0Smrg			  mode);
113942542f5fSchristos	_kgem_set_mode(&sna->kgem, mode);
114042542f5fSchristos}
114142542f5fSchristos
114242542f5fSchristosstatic bool is_front(int attachment)
114342542f5fSchristos{
114442542f5fSchristos	return attachment == DRI2BufferFrontLeft;
114542542f5fSchristos}
114642542f5fSchristos
114763ef14f0Smrg#define DRI2_SYNC 0x1
114863ef14f0Smrg#define DRI2_DAMAGE 0x2
114963ef14f0Smrg#define DRI2_BO 0x4
115042542f5fSchristosstatic struct kgem_bo *
115142542f5fSchristos__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
115242542f5fSchristos		      DRI2BufferPtr src, DRI2BufferPtr dst,
115363ef14f0Smrg		      unsigned flags)
115442542f5fSchristos{
115542542f5fSchristos	PixmapPtr pixmap = get_drawable_pixmap(draw);
115642542f5fSchristos	DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable;
115742542f5fSchristos	struct sna_dri2_private *src_priv = get_private(src);
115842542f5fSchristos	struct sna_dri2_private *dst_priv = get_private(dst);
115942542f5fSchristos	pixman_region16_t clip;
116042542f5fSchristos	struct kgem_bo *bo = NULL;
116142542f5fSchristos	struct kgem_bo *src_bo;
116242542f5fSchristos	struct kgem_bo *dst_bo;
116342542f5fSchristos	const BoxRec *boxes;
116442542f5fSchristos	int16_t dx, dy, sx, sy;
116563ef14f0Smrg	unsigned hint;
116642542f5fSchristos	int n;
116742542f5fSchristos
116842542f5fSchristos	/* To hide a stale DRI2Buffer, one may choose to substitute
116942542f5fSchristos	 * pixmap->gpu_bo instead of dst/src->bo, however you then run
117042542f5fSchristos	 * the risk of copying around invalid data. So either you may not
117142542f5fSchristos	 * see the results of the copy, or you may see the wrong pixels.
117242542f5fSchristos	 * Either way you eventually lose.
117342542f5fSchristos	 *
117442542f5fSchristos	 * We also have to be careful in case that the stale buffers are
117542542f5fSchristos	 * now attached to invalid (non-DRI) pixmaps.
117642542f5fSchristos	 */
117742542f5fSchristos
117842542f5fSchristos	assert(is_front(dst->attachment) || is_front(src->attachment));
117942542f5fSchristos	assert(dst->attachment != src->attachment);
118042542f5fSchristos
118142542f5fSchristos	clip.extents.x1 = draw->x;
118242542f5fSchristos	clip.extents.y1 = draw->y;
118342542f5fSchristos	clip.extents.x2 = draw->x + draw->width;
118442542f5fSchristos	clip.extents.y2 = draw->y + draw->height;
118542542f5fSchristos	clip.data = NULL;
118642542f5fSchristos
118742542f5fSchristos	if (region) {
118842542f5fSchristos		pixman_region_translate(region, draw->x, draw->y);
118942542f5fSchristos		pixman_region_intersect(&clip, &clip, region);
119042542f5fSchristos		region = &clip;
119142542f5fSchristos	}
119242542f5fSchristos
119342542f5fSchristos	if (clip.extents.x1 >= clip.extents.x2 ||
119442542f5fSchristos	    clip.extents.y1 >= clip.extents.y2) {
119542542f5fSchristos		DBG(("%s: all clipped\n", __FUNCTION__));
119642542f5fSchristos		return NULL;
119742542f5fSchristos	}
119842542f5fSchristos
119942542f5fSchristos	sx = sy = dx = dy = 0;
120042542f5fSchristos	if (is_front(dst->attachment)) {
120142542f5fSchristos		sx = -draw->x;
120242542f5fSchristos		sy = -draw->y;
120342542f5fSchristos	} else {
120442542f5fSchristos		dx = -draw->x;
120542542f5fSchristos		dy = -draw->y;
120642542f5fSchristos	}
120742542f5fSchristos	if (draw->type == DRAWABLE_WINDOW) {
120842542f5fSchristos		WindowPtr win = (WindowPtr)draw;
120942542f5fSchristos		int16_t tx, ty;
121042542f5fSchristos
121142542f5fSchristos		if (is_clipped(&win->clipList, draw)) {
121242542f5fSchristos			DBG(("%s: draw=(%d, %d), delta=(%d, %d), draw=(%d, %d),(%d, %d), clip.extents=(%d, %d), (%d, %d)\n",
121342542f5fSchristos			     __FUNCTION__, draw->x, draw->y,
121442542f5fSchristos			     get_drawable_dx(draw), get_drawable_dy(draw),
121542542f5fSchristos			     clip.extents.x1, clip.extents.y1,
121642542f5fSchristos			     clip.extents.x2, clip.extents.y2,
121742542f5fSchristos			     win->clipList.extents.x1, win->clipList.extents.y1,
121842542f5fSchristos			     win->clipList.extents.x2, win->clipList.extents.y2));
121942542f5fSchristos
122042542f5fSchristos			assert(region == NULL || region == &clip);
122142542f5fSchristos			pixman_region_intersect(&clip, &win->clipList, &clip);
122242542f5fSchristos			if (!pixman_region_not_empty(&clip)) {
122342542f5fSchristos				DBG(("%s: all clipped\n", __FUNCTION__));
122442542f5fSchristos				return NULL;
122542542f5fSchristos			}
122642542f5fSchristos
122742542f5fSchristos			region = &clip;
122842542f5fSchristos		}
122942542f5fSchristos
123042542f5fSchristos		if (get_drawable_deltas(draw, pixmap, &tx, &ty)) {
123142542f5fSchristos			if (is_front(dst->attachment)) {
123242542f5fSchristos				pixman_region_translate(region ?: &clip, tx, ty);
123342542f5fSchristos				sx -= tx;
123442542f5fSchristos				sy -= ty;
123542542f5fSchristos			} else {
123642542f5fSchristos				sx += tx;
123742542f5fSchristos				sy += ty;
123842542f5fSchristos			}
123942542f5fSchristos		}
124042542f5fSchristos	} else
124163ef14f0Smrg		flags &= ~DRI2_SYNC;
124242542f5fSchristos
124363ef14f0Smrg	scratch.pScreen = draw->pScreen;
124442542f5fSchristos	scratch.x = scratch.y = 0;
124542542f5fSchristos	scratch.width = scratch.height = 0;
124642542f5fSchristos	scratch.depth = draw->depth;
124742542f5fSchristos	scratch.bitsPerPixel = draw->bitsPerPixel;
124842542f5fSchristos
124942542f5fSchristos	src_bo = src_priv->bo;
125042542f5fSchristos	assert(src_bo->refcnt);
125163ef14f0Smrg	kgem_bo_unclean(&sna->kgem, src_bo);
125242542f5fSchristos	if (is_front(src->attachment)) {
125342542f5fSchristos		struct sna_pixmap *priv;
125442542f5fSchristos
125542542f5fSchristos		priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ);
125642542f5fSchristos		if (priv)
125742542f5fSchristos			src_bo = priv->gpu_bo;
125842542f5fSchristos		DBG(("%s: updated FrontLeft src_bo from handle=%d to handle=%d\n",
125942542f5fSchristos		     __FUNCTION__, src_priv->bo->handle, src_bo->handle));
126042542f5fSchristos		assert(src_bo->refcnt);
126142542f5fSchristos	} else {
126242542f5fSchristos		RegionRec source;
126342542f5fSchristos
126442542f5fSchristos		scratch.width = src_priv->size & 0xffff;
126542542f5fSchristos		scratch.height = src_priv->size >> 16;
126642542f5fSchristos		src_draw = &scratch;
126742542f5fSchristos
126863ef14f0Smrg		DBG(("%s: source size %dx%d, region size %dx%d, src offset %dx%d\n",
126942542f5fSchristos		     __FUNCTION__,
127042542f5fSchristos		     scratch.width, scratch.height,
127142542f5fSchristos		     clip.extents.x2 - clip.extents.x1,
127263ef14f0Smrg		     clip.extents.y2 - clip.extents.y1,
127363ef14f0Smrg		     -sx, -sy));
127442542f5fSchristos
127542542f5fSchristos		source.extents.x1 = -sx;
127642542f5fSchristos		source.extents.y1 = -sy;
127742542f5fSchristos		source.extents.x2 = source.extents.x1 + scratch.width;
127842542f5fSchristos		source.extents.y2 = source.extents.y1 + scratch.height;
127942542f5fSchristos		source.data = NULL;
128042542f5fSchristos
128142542f5fSchristos		assert(region == NULL || region == &clip);
128242542f5fSchristos		pixman_region_intersect(&clip, &clip, &source);
128342542f5fSchristos
128463ef14f0Smrg		if (!pixman_region_not_empty(&clip)) {
128563ef14f0Smrg			DBG(("%s: region doesn't overlap pixmap\n", __FUNCTION__));
128663ef14f0Smrg			return NULL;
128763ef14f0Smrg		}
128842542f5fSchristos	}
128942542f5fSchristos
129042542f5fSchristos	dst_bo = dst_priv->bo;
129142542f5fSchristos	assert(dst_bo->refcnt);
129242542f5fSchristos	if (is_front(dst->attachment)) {
129342542f5fSchristos		struct sna_pixmap *priv;
129413496ba1Ssnj		struct list shadow;
129513496ba1Ssnj
129613496ba1Ssnj		/* Preserve the CRTC shadow overrides */
129713496ba1Ssnj		sna_shadow_steal_crtcs(sna, &shadow);
129842542f5fSchristos
129963ef14f0Smrg		hint = MOVE_WRITE | __MOVE_FORCE;
130042542f5fSchristos		if (clip.data)
130163ef14f0Smrg			hint |= MOVE_READ;
130242542f5fSchristos
130342542f5fSchristos		assert(region == NULL || region == &clip);
130463ef14f0Smrg		priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, hint);
130542542f5fSchristos		if (priv) {
130663ef14f0Smrg			damage(pixmap, priv, region ?: &clip);
130742542f5fSchristos			dst_bo = priv->gpu_bo;
130842542f5fSchristos		}
130942542f5fSchristos		DBG(("%s: updated FrontLeft dst_bo from handle=%d to handle=%d\n",
131042542f5fSchristos		     __FUNCTION__, dst_priv->bo->handle, dst_bo->handle));
131142542f5fSchristos		assert(dst_bo->refcnt);
131213496ba1Ssnj
131313496ba1Ssnj		sna_shadow_unsteal_crtcs(sna, &shadow);
131442542f5fSchristos	} else {
131542542f5fSchristos		RegionRec target;
131642542f5fSchristos
131742542f5fSchristos		scratch.width = dst_priv->size & 0xffff;
131842542f5fSchristos		scratch.height = dst_priv->size >> 16;
131942542f5fSchristos		dst_draw = &scratch;
132042542f5fSchristos
132142542f5fSchristos		DBG(("%s: target size %dx%d, region size %dx%d\n",
132242542f5fSchristos		     __FUNCTION__,
132342542f5fSchristos		     scratch.width, scratch.height,
132442542f5fSchristos		     clip.extents.x2 - clip.extents.x1,
132542542f5fSchristos		     clip.extents.y2 - clip.extents.y1));
132642542f5fSchristos
132742542f5fSchristos		target.extents.x1 = -dx;
132842542f5fSchristos		target.extents.y1 = -dy;
132942542f5fSchristos		target.extents.x2 = target.extents.x1 + scratch.width;
133042542f5fSchristos		target.extents.y2 = target.extents.y1 + scratch.height;
133142542f5fSchristos		target.data = NULL;
133242542f5fSchristos
133342542f5fSchristos		assert(region == NULL || region == &clip);
133442542f5fSchristos		pixman_region_intersect(&clip, &clip, &target);
133542542f5fSchristos
133663ef14f0Smrg		flags &= ~DRI2_SYNC;
133742542f5fSchristos	}
133842542f5fSchristos
133942542f5fSchristos	if (!wedged(sna)) {
134042542f5fSchristos		xf86CrtcPtr crtc;
134142542f5fSchristos
134242542f5fSchristos		crtc = NULL;
134363ef14f0Smrg		if (flags & DRI2_SYNC && sna_pixmap_is_scanout(sna, pixmap))
134442542f5fSchristos			crtc = sna_covering_crtc(sna, &clip.extents, NULL);
134542542f5fSchristos		sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL);
134642542f5fSchristos
134763ef14f0Smrg		if (crtc == NULL ||
134863ef14f0Smrg		    !sna_wait_for_scanline(sna, pixmap, crtc, &clip.extents))
134963ef14f0Smrg			flags &= ~DRI2_SYNC;
135042542f5fSchristos	}
135142542f5fSchristos
135242542f5fSchristos	if (region) {
135342542f5fSchristos		boxes = region_rects(region);
135442542f5fSchristos		n = region_num_rects(region);
135542542f5fSchristos		assert(n);
135642542f5fSchristos	} else {
135742542f5fSchristos		region = &clip;
135842542f5fSchristos		boxes = &clip.extents;
135942542f5fSchristos		n = 1;
136042542f5fSchristos	}
136163ef14f0Smrg	if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
136263ef14f0Smrg		DBG(("%s: marking region as damaged\n", __FUNCTION__));
136363ef14f0Smrg		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
136463ef14f0Smrg		DamageRegionAppend(&pixmap->drawable, region);
136563ef14f0Smrg	}
136642542f5fSchristos
136713496ba1Ssnj	DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n",
136813496ba1Ssnj	     __FUNCTION__,
136913496ba1Ssnj	     boxes[0].x1, boxes[0].y1,
137013496ba1Ssnj	     boxes[0].x2, boxes[0].y2,
137113496ba1Ssnj	     n, sx, sy, dx, dy));
137213496ba1Ssnj
137363ef14f0Smrg	hint = COPY_LAST | COPY_DRI;
137463ef14f0Smrg	if (flags & DRI2_SYNC)
137563ef14f0Smrg		hint |= COPY_SYNC;
137613496ba1Ssnj	if (!sna->render.copy_boxes(sna, GXcopy,
137713496ba1Ssnj				    src_draw, src_bo, sx, sy,
137813496ba1Ssnj				    dst_draw, dst_bo, dx, dy,
137963ef14f0Smrg				    boxes, n, hint))
138013496ba1Ssnj		memcpy_copy_boxes(sna, GXcopy,
138113496ba1Ssnj				  src_draw, src_bo, sx, sy,
138213496ba1Ssnj				  dst_draw, dst_bo, dx, dy,
138363ef14f0Smrg				  boxes, n, hint);
138463ef14f0Smrg
138563ef14f0Smrg	sna->needs_dri_flush = true;
138663ef14f0Smrg	if (flags & (DRI2_SYNC | DRI2_BO)) { /* STAT! */
138763ef14f0Smrg		struct kgem_request *rq = RQ(dst_bo->rq);
138863ef14f0Smrg		if (rq && rq != (void *)&sna->kgem) {
138963ef14f0Smrg			if (rq->bo == NULL)
139063ef14f0Smrg				kgem_submit(&sna->kgem);
139163ef14f0Smrg			if (rq->bo) { /* Becareful in case the gpu is wedged */
139263ef14f0Smrg				bo = ref(rq->bo);
139363ef14f0Smrg				DBG(("%s: recording sync fence handle=%d\n",
139463ef14f0Smrg				     __FUNCTION__, bo->handle));
139563ef14f0Smrg			}
139642542f5fSchristos		}
139742542f5fSchristos	}
139842542f5fSchristos
139963ef14f0Smrg	if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
140063ef14f0Smrg		sna->ignore_copy_area = false;
140163ef14f0Smrg		DamageRegionProcessPending(&pixmap->drawable);
140263ef14f0Smrg	}
140342542f5fSchristos
140442542f5fSchristos	if (clip.data)
140542542f5fSchristos		pixman_region_fini(&clip);
140642542f5fSchristos
140742542f5fSchristos	return bo;
140842542f5fSchristos}
140942542f5fSchristos
141042542f5fSchristosstatic void
141142542f5fSchristossna_dri2_copy_region(DrawablePtr draw,
141242542f5fSchristos		     RegionPtr region,
141342542f5fSchristos		     DRI2BufferPtr dst,
141442542f5fSchristos		     DRI2BufferPtr src)
141542542f5fSchristos{
141642542f5fSchristos	PixmapPtr pixmap = get_drawable_pixmap(draw);
141742542f5fSchristos	struct sna *sna = to_sna_from_pixmap(pixmap);
141842542f5fSchristos
141942542f5fSchristos	DBG(("%s: pixmap=%ld, src=%u (refs=%d/%d, flush=%d, attach=%d) , dst=%u (refs=%d/%d, flush=%d, attach=%d)\n",
142042542f5fSchristos	     __FUNCTION__,
142142542f5fSchristos	     pixmap->drawable.serialNumber,
142242542f5fSchristos	     get_private(src)->bo->handle,
142342542f5fSchristos	     get_private(src)->refcnt,
142442542f5fSchristos	     get_private(src)->bo->refcnt,
142542542f5fSchristos	     get_private(src)->bo->flush,
142642542f5fSchristos	     src->attachment,
142742542f5fSchristos	     get_private(dst)->bo->handle,
142842542f5fSchristos	     get_private(dst)->refcnt,
142942542f5fSchristos	     get_private(dst)->bo->refcnt,
143042542f5fSchristos	     get_private(dst)->bo->flush,
143142542f5fSchristos	     dst->attachment));
143242542f5fSchristos
143342542f5fSchristos	assert(src != dst);
143442542f5fSchristos
143542542f5fSchristos	assert(get_private(src)->refcnt);
143642542f5fSchristos	assert(get_private(dst)->refcnt);
143742542f5fSchristos
143863ef14f0Smrg	assert(get_private(src)->bo != get_private(dst)->bo);
143963ef14f0Smrg
144042542f5fSchristos	assert(get_private(src)->bo->refcnt);
144142542f5fSchristos	assert(get_private(dst)->bo->refcnt);
144242542f5fSchristos
144342542f5fSchristos	DBG(("%s: region (%d, %d), (%d, %d) x %d\n",
144442542f5fSchristos	     __FUNCTION__,
144542542f5fSchristos	     region->extents.x1, region->extents.y1,
144642542f5fSchristos	     region->extents.x2, region->extents.y2,
144742542f5fSchristos	     region_num_rects(region)));
144842542f5fSchristos
144963ef14f0Smrg	__sna_dri2_copy_region(sna, draw, region, src, dst, DRI2_DAMAGE);
145042542f5fSchristos}
145142542f5fSchristos
145242542f5fSchristosinline static uint32_t pipe_select(int pipe)
145342542f5fSchristos{
145442542f5fSchristos	/* The third pipe was introduced with IvyBridge long after
145542542f5fSchristos	 * multiple pipe support was added to the kernel, hence
145642542f5fSchristos	 * we can safely ignore the capability check - if we have more
145742542f5fSchristos	 * than two pipes, we can assume that they are fully supported.
145842542f5fSchristos	 */
145963ef14f0Smrg	assert(pipe < _DRM_VBLANK_HIGH_CRTC_MASK);
146042542f5fSchristos	if (pipe > 1)
146142542f5fSchristos		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
146242542f5fSchristos	else if (pipe > 0)
146342542f5fSchristos		return DRM_VBLANK_SECONDARY;
146442542f5fSchristos	else
146542542f5fSchristos		return 0;
146642542f5fSchristos}
146742542f5fSchristos
146863ef14f0Smrgstatic inline bool sna_next_vblank(struct sna_dri2_event *info)
146942542f5fSchristos{
147063ef14f0Smrg	union drm_wait_vblank vbl;
147142542f5fSchristos
147263ef14f0Smrg	DBG(("%s(pipe=%d, waiting until next vblank)\n",
147363ef14f0Smrg	     __FUNCTION__, info->pipe));
147463ef14f0Smrg	assert(info->pipe != -1);
147563ef14f0Smrg
147663ef14f0Smrg	VG_CLEAR(vbl);
147763ef14f0Smrg	vbl.request.type =
147863ef14f0Smrg		DRM_VBLANK_RELATIVE |
147963ef14f0Smrg		DRM_VBLANK_EVENT |
148063ef14f0Smrg		pipe_select(info->pipe);
148163ef14f0Smrg	vbl.request.sequence = 1;
148263ef14f0Smrg	vbl.request.signal = (uintptr_t)info;
148363ef14f0Smrg
148463ef14f0Smrg	assert(!info->queued);
148563ef14f0Smrg	if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
148663ef14f0Smrg		return false;
148763ef14f0Smrg
148863ef14f0Smrg	info->queued = true;
148963ef14f0Smrg	return true;
149063ef14f0Smrg}
149163ef14f0Smrg
149263ef14f0Smrgstatic inline bool sna_wait_vblank(struct sna_dri2_event *info,
149363ef14f0Smrg				   unsigned seq)
149463ef14f0Smrg{
149563ef14f0Smrg	union drm_wait_vblank vbl;
149663ef14f0Smrg
149763ef14f0Smrg	DBG(("%s(pipe=%d, waiting until vblank %u)\n",
149863ef14f0Smrg	     __FUNCTION__, info->pipe, seq));
149963ef14f0Smrg	assert(info->pipe != -1);
150063ef14f0Smrg
150163ef14f0Smrg	VG_CLEAR(vbl);
150263ef14f0Smrg	vbl.request.type =
150363ef14f0Smrg		DRM_VBLANK_ABSOLUTE |
150463ef14f0Smrg		DRM_VBLANK_EVENT |
150563ef14f0Smrg		pipe_select(info->pipe);
150663ef14f0Smrg	vbl.request.sequence = seq;
150763ef14f0Smrg	vbl.request.signal = (uintptr_t)info;
150863ef14f0Smrg
150963ef14f0Smrg	assert(!info->queued);
151063ef14f0Smrg	if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
151163ef14f0Smrg		return false;
151263ef14f0Smrg
151363ef14f0Smrg	info->queued = true;
151463ef14f0Smrg	return true;
151542542f5fSchristos}
151642542f5fSchristos
151742542f5fSchristos#if DRI2INFOREC_VERSION >= 4
151842542f5fSchristos
151942542f5fSchristosstatic void dri2_window_attach(WindowPtr win, struct dri2_window *priv)
152042542f5fSchristos{
152142542f5fSchristos	assert(win->drawable.type == DRAWABLE_WINDOW);
152242542f5fSchristos	assert(dri2_window(win) == NULL);
152342542f5fSchristos	((void **)__get_private(win, sna_window_key))[1] = priv;
152442542f5fSchristos	assert(dri2_window(win) == priv);
152542542f5fSchristos}
152642542f5fSchristos
152742542f5fSchristosstatic uint64_t
152842542f5fSchristosdraw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
152942542f5fSchristos{
153042542f5fSchristos	struct dri2_window *priv;
153142542f5fSchristos
153263ef14f0Smrg	assert(draw);
153342542f5fSchristos	if (draw->type != DRAWABLE_WINDOW)
153442542f5fSchristos		return msc;
153542542f5fSchristos
153642542f5fSchristos	priv = dri2_window((WindowPtr)draw);
153742542f5fSchristos	if (priv == NULL) {
153842542f5fSchristos		priv = malloc(sizeof(*priv));
153942542f5fSchristos		if (priv != NULL) {
154042542f5fSchristos			priv->front = NULL;
154142542f5fSchristos			priv->crtc = crtc;
154242542f5fSchristos			priv->msc_delta = 0;
154342542f5fSchristos			priv->chain = NULL;
154463ef14f0Smrg			priv->cache_size = 0;
154563ef14f0Smrg			list_init(&priv->cache);
154642542f5fSchristos			dri2_window_attach((WindowPtr)draw, priv);
154742542f5fSchristos		}
154842542f5fSchristos	} else {
154942542f5fSchristos		if (priv->crtc != crtc) {
155042542f5fSchristos			const struct ust_msc *last = sna_crtc_last_swap(priv->crtc);
155142542f5fSchristos			const struct ust_msc *this = sna_crtc_last_swap(crtc);
155242542f5fSchristos			DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
155342542f5fSchristos			     __FUNCTION__,
155463ef14f0Smrg			     sna_crtc_pipe(priv->crtc), (long long)last->msc,
155563ef14f0Smrg			     sna_crtc_pipe(crtc), (long long)this->msc,
155642542f5fSchristos			     (long long)(priv->msc_delta + this->msc - last->msc)));
155742542f5fSchristos			priv->msc_delta += this->msc - last->msc;
155842542f5fSchristos			priv->crtc = crtc;
155942542f5fSchristos		}
156042542f5fSchristos		msc -= priv->msc_delta;
156142542f5fSchristos	}
156242542f5fSchristos	return  msc;
156342542f5fSchristos}
156442542f5fSchristos
156542542f5fSchristosstatic uint32_t
156642542f5fSchristosdraw_target_seq(DrawablePtr draw, uint64_t msc)
156742542f5fSchristos{
156842542f5fSchristos	struct dri2_window *priv = dri2_window((WindowPtr)draw);
156942542f5fSchristos	if (priv == NULL)
157042542f5fSchristos		return msc;
157142542f5fSchristos	DBG(("%s: converting target_msc=%llu to seq %u\n",
157242542f5fSchristos	     __FUNCTION__, (long long)msc, (unsigned)(msc + priv->msc_delta)));
157342542f5fSchristos	return msc + priv->msc_delta;
157442542f5fSchristos}
157542542f5fSchristos
157642542f5fSchristosstatic xf86CrtcPtr
157742542f5fSchristossna_dri2_get_crtc(DrawablePtr draw)
157842542f5fSchristos{
157942542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
158042542f5fSchristos		return NULL;
158142542f5fSchristos
158242542f5fSchristos	/* Make sure the CRTC is valid and this is the real front buffer */
158313496ba1Ssnj	return sna_covering_crtc(to_sna_from_drawable(draw),
158413496ba1Ssnj				 &((WindowPtr)draw)->clipList.extents,
158513496ba1Ssnj				 NULL);
158642542f5fSchristos}
158742542f5fSchristos
158863ef14f0Smrgstatic void frame_swap_complete(struct sna_dri2_event *frame, int type)
158942542f5fSchristos{
159063ef14f0Smrg	const struct ust_msc *swap;
159142542f5fSchristos
159263ef14f0Smrg	assert(frame->signal);
159363ef14f0Smrg	frame->signal = false;
159442542f5fSchristos
159563ef14f0Smrg	if (frame->client == NULL) {
159663ef14f0Smrg		DBG(("%s: client already gone\n", __FUNCTION__));
159742542f5fSchristos		return;
159842542f5fSchristos	}
159942542f5fSchristos
160063ef14f0Smrg	assert(frame->draw);
160163ef14f0Smrg
160263ef14f0Smrg	swap = sna_crtc_last_swap(frame->crtc);
160363ef14f0Smrg	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
160463ef14f0Smrg	     __FUNCTION__, type, (long)frame->draw->id, frame->pipe,
160563ef14f0Smrg	     (long long)swap->msc,
160663ef14f0Smrg	     (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
160763ef14f0Smrg	     swap->tv_sec, swap->tv_usec));
160863ef14f0Smrg
160963ef14f0Smrg	DRI2SwapComplete(frame->client, frame->draw,
161063ef14f0Smrg			 draw_current_msc(frame->draw, frame->crtc, swap->msc),
161163ef14f0Smrg			 swap->tv_sec, swap->tv_usec,
161263ef14f0Smrg			 type, frame->event_complete, frame->event_data);
161342542f5fSchristos}
161442542f5fSchristos
161563ef14f0Smrgstatic void fake_swap_complete(struct sna *sna, ClientPtr client,
161663ef14f0Smrg			       DrawablePtr draw, xf86CrtcPtr crtc,
161763ef14f0Smrg			       int type, DRI2SwapEventPtr func, void *data)
161842542f5fSchristos{
161963ef14f0Smrg	const struct ust_msc *swap;
162042542f5fSchristos
162163ef14f0Smrg	assert(draw);
162242542f5fSchristos
162363ef14f0Smrg	if (crtc == NULL)
162463ef14f0Smrg		crtc = sna_primary_crtc(sna);
162542542f5fSchristos
162663ef14f0Smrg	swap = sna_crtc_last_swap(crtc);
162763ef14f0Smrg	DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
162863ef14f0Smrg	     __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1,
162963ef14f0Smrg	     (long long)swap->msc,
163063ef14f0Smrg	     (long long)draw_current_msc(draw, crtc, swap->msc),
163163ef14f0Smrg	     swap->tv_sec, swap->tv_usec));
163242542f5fSchristos
163363ef14f0Smrg	DRI2SwapComplete(client, draw,
163463ef14f0Smrg			 draw_current_msc(draw, crtc, swap->msc),
163563ef14f0Smrg			 swap->tv_sec, swap->tv_usec,
163663ef14f0Smrg			 type, func, data);
163763ef14f0Smrg}
163842542f5fSchristos
163963ef14f0Smrgstatic void
164063ef14f0Smrgsna_dri2_remove_event(struct sna_dri2_event *info)
164163ef14f0Smrg{
164263ef14f0Smrg	WindowPtr win = (WindowPtr)info->draw;
164363ef14f0Smrg	struct dri2_window *priv;
164442542f5fSchristos
164563ef14f0Smrg	assert(win->drawable.type == DRAWABLE_WINDOW);
164663ef14f0Smrg	DBG(("%s: remove[%p] from window %ld, active? %d\n",
164763ef14f0Smrg	     __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
164863ef14f0Smrg	assert(!info->signal);
164963ef14f0Smrg
165063ef14f0Smrg	priv = dri2_window(win);
165163ef14f0Smrg	assert(priv);
165263ef14f0Smrg	assert(priv->chain != NULL);
165363ef14f0Smrg	assert(info->chained);
165463ef14f0Smrg	info->chained = false;
165563ef14f0Smrg
165663ef14f0Smrg	if (priv->chain != info) {
165763ef14f0Smrg		struct sna_dri2_event *chain = priv->chain;
165863ef14f0Smrg		while (chain->chain != info) {
165963ef14f0Smrg			assert(chain->chained);
166063ef14f0Smrg			chain = chain->chain;
166163ef14f0Smrg		}
166263ef14f0Smrg		assert(chain != info);
166363ef14f0Smrg		assert(info->chain != chain);
166463ef14f0Smrg		chain->chain = info->chain;
166563ef14f0Smrg		return;
166663ef14f0Smrg	}
166763ef14f0Smrg
166863ef14f0Smrg	priv->chain = info->chain;
166963ef14f0Smrg	if (priv->chain == NULL) {
167063ef14f0Smrg		struct dri_bo *c, *tmp;
167163ef14f0Smrg
167263ef14f0Smrg		c = list_entry(priv->cache.next->next, struct dri_bo, link);
167363ef14f0Smrg		list_for_each_entry_safe_from(c, tmp, &priv->cache, link) {
167463ef14f0Smrg			list_del(&c->link);
167563ef14f0Smrg
167663ef14f0Smrg			DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
167763ef14f0Smrg			assert(c->bo);
167863ef14f0Smrg			kgem_bo_destroy(&info->sna->kgem, c->bo);
167963ef14f0Smrg			free(c);
168063ef14f0Smrg		}
168142542f5fSchristos	}
168263ef14f0Smrg}
168363ef14f0Smrg
168463ef14f0Smrgstatic void
168563ef14f0Smrgsna_dri2_event_free(struct sna_dri2_event *info)
168663ef14f0Smrg{
168763ef14f0Smrg	DBG(("%s(draw?=%d)\n", __FUNCTION__, info->draw != NULL));
168863ef14f0Smrg	assert(!info->queued);
168963ef14f0Smrg	assert(!info->signal);
169063ef14f0Smrg	assert(info->pending.bo == NULL);
169163ef14f0Smrg
169263ef14f0Smrg	if (info->sna->dri2.flip_pending == info)
169363ef14f0Smrg		info->sna->dri2.flip_pending = NULL;
169463ef14f0Smrg	assert(info->sna->dri2.flip_pending != info);
169563ef14f0Smrg	if (info->chained)
169663ef14f0Smrg		sna_dri2_remove_event(info);
169763ef14f0Smrg
169863ef14f0Smrg	assert((info->front == NULL && info->back == NULL) || info->front != info->back);
169963ef14f0Smrg	_sna_dri2_destroy_buffer(info->sna, info->draw, info->front);
170063ef14f0Smrg	_sna_dri2_destroy_buffer(info->sna, info->draw, info->back);
170142542f5fSchristos
170242542f5fSchristos	if (info->bo) {
170342542f5fSchristos		DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
170413496ba1Ssnj		kgem_bo_destroy(&info->sna->kgem, info->bo);
170542542f5fSchristos	}
170642542f5fSchristos
170742542f5fSchristos	_list_del(&info->link);
170842542f5fSchristos	free(info);
170942542f5fSchristos}
171042542f5fSchristos
171142542f5fSchristosstatic void
171242542f5fSchristossna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
171342542f5fSchristos{
171442542f5fSchristos	NewClientInfoRec *clientinfo = data;
171542542f5fSchristos	ClientPtr client = clientinfo->client;
171642542f5fSchristos	struct sna_client *priv = sna_client(client);
171742542f5fSchristos	struct sna *sna = closure;
171842542f5fSchristos
171942542f5fSchristos	if (priv->events.next == NULL)
172042542f5fSchristos		return;
172142542f5fSchristos
172242542f5fSchristos	if (client->clientState != ClientStateGone)
172342542f5fSchristos		return;
172442542f5fSchristos
172542542f5fSchristos	DBG(("%s(active?=%d)\n", __FUNCTION__,
172642542f5fSchristos	     !list_is_empty(&priv->events)));
172742542f5fSchristos
172842542f5fSchristos	while (!list_is_empty(&priv->events)) {
172942542f5fSchristos		struct sna_dri2_event *event;
173042542f5fSchristos
173142542f5fSchristos		event = list_first_entry(&priv->events, struct sna_dri2_event, link);
173242542f5fSchristos		assert(event->client == client);
173363ef14f0Smrg		list_del(&event->link);
173463ef14f0Smrg		event->signal = false;
173542542f5fSchristos
173663ef14f0Smrg		if (event->pending.bo) {
173763ef14f0Smrg			assert(event->pending.bo->active_scanout > 0);
173863ef14f0Smrg			event->pending.bo->active_scanout--;
173963ef14f0Smrg
174063ef14f0Smrg			kgem_bo_destroy(&sna->kgem, event->pending.bo);
174163ef14f0Smrg			event->pending.bo = NULL;
174263ef14f0Smrg		}
174363ef14f0Smrg
174463ef14f0Smrg		if (event->chained)
174563ef14f0Smrg			sna_dri2_remove_event(event);
174663ef14f0Smrg
174763ef14f0Smrg		event->client = NULL;
174863ef14f0Smrg		event->draw = NULL;
174963ef14f0Smrg		event->keepalive = 1;
175063ef14f0Smrg		assert(!event->signal);
175163ef14f0Smrg
175263ef14f0Smrg		if (!event->queued)
175313496ba1Ssnj			sna_dri2_event_free(event);
175442542f5fSchristos	}
175542542f5fSchristos
175642542f5fSchristos	if (--sna->dri2.client_count == 0)
175742542f5fSchristos		DeleteCallback(&ClientStateCallback, sna_dri2_client_gone, sna);
175842542f5fSchristos}
175942542f5fSchristos
176042542f5fSchristosstatic bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, ClientPtr client)
176142542f5fSchristos{
176242542f5fSchristos	struct sna_client *priv = sna_client(client);
176342542f5fSchristos
176442542f5fSchristos	if (priv->events.next == NULL) {
176542542f5fSchristos		if (sna->dri2.client_count++ == 0 &&
176642542f5fSchristos		    !AddCallback(&ClientStateCallback, sna_dri2_client_gone, sna))
176742542f5fSchristos			return false;
176842542f5fSchristos
176942542f5fSchristos		list_init(&priv->events);
177042542f5fSchristos	}
177142542f5fSchristos
177242542f5fSchristos	list_add(&info->link, &priv->events);
177342542f5fSchristos	info->client = client;
177442542f5fSchristos	return true;
177542542f5fSchristos}
177642542f5fSchristos
177742542f5fSchristosstatic struct sna_dri2_event *
177863ef14f0Smrgsna_dri2_add_event(struct sna *sna,
177963ef14f0Smrg		   DrawablePtr draw,
178063ef14f0Smrg		   ClientPtr client,
178163ef14f0Smrg		   xf86CrtcPtr crtc)
178242542f5fSchristos{
178342542f5fSchristos	struct dri2_window *priv;
178442542f5fSchristos	struct sna_dri2_event *info, *chain;
178542542f5fSchristos
178663ef14f0Smrg	assert(draw != NULL);
178742542f5fSchristos	assert(draw->type == DRAWABLE_WINDOW);
178842542f5fSchristos	DBG(("%s: adding event to window %ld)\n",
178942542f5fSchristos	     __FUNCTION__, (long)draw->id));
179042542f5fSchristos
179142542f5fSchristos	priv = dri2_window((WindowPtr)draw);
179242542f5fSchristos	if (priv == NULL)
179342542f5fSchristos		return NULL;
179442542f5fSchristos
179542542f5fSchristos	info = calloc(1, sizeof(struct sna_dri2_event));
179642542f5fSchristos	if (info == NULL)
179742542f5fSchristos		return NULL;
179842542f5fSchristos
179913496ba1Ssnj	info->sna = sna;
180042542f5fSchristos	info->draw = draw;
180163ef14f0Smrg	info->crtc = crtc;
180263ef14f0Smrg	info->pipe = sna_crtc_pipe(crtc);
180363ef14f0Smrg	info->keepalive = 1;
180442542f5fSchristos
180542542f5fSchristos	if (!add_event_to_client(info, sna, client)) {
180642542f5fSchristos		free(info);
180742542f5fSchristos		return NULL;
180842542f5fSchristos	}
180942542f5fSchristos
181042542f5fSchristos	assert(priv->chain != info);
181163ef14f0Smrg	info->chained = true;
181242542f5fSchristos
181342542f5fSchristos	if (priv->chain == NULL) {
181442542f5fSchristos		priv->chain = info;
181542542f5fSchristos		return info;
181642542f5fSchristos	}
181742542f5fSchristos
181842542f5fSchristos	chain = priv->chain;
181942542f5fSchristos	while (chain->chain != NULL)
182042542f5fSchristos		chain = chain->chain;
182142542f5fSchristos
182242542f5fSchristos	assert(chain != info);
182342542f5fSchristos	chain->chain = info;
182442542f5fSchristos	return info;
182542542f5fSchristos}
182642542f5fSchristos
182763ef14f0Smrgstatic void decouple_window(WindowPtr win,
182863ef14f0Smrg			    struct dri2_window *priv,
182963ef14f0Smrg			    struct sna *sna,
183063ef14f0Smrg			    bool signal)
183113496ba1Ssnj{
183213496ba1Ssnj	if (priv->front) {
183363ef14f0Smrg		DBG(("%s: decouple private front\n", __FUNCTION__));
183413496ba1Ssnj		assert(priv->crtc);
183513496ba1Ssnj		sna_shadow_unset_crtc(sna, priv->crtc);
183613496ba1Ssnj
183763ef14f0Smrg		_sna_dri2_destroy_buffer(sna, NULL, priv->front);
183863ef14f0Smrg		priv->front = NULL;
183942542f5fSchristos	}
184042542f5fSchristos
184142542f5fSchristos	if (priv->chain) {
184242542f5fSchristos		struct sna_dri2_event *info, *chain;
184342542f5fSchristos
184442542f5fSchristos		DBG(("%s: freeing chain\n", __FUNCTION__));
184542542f5fSchristos
184642542f5fSchristos		chain = priv->chain;
184742542f5fSchristos		while ((info = chain)) {
184863ef14f0Smrg			DBG(("%s: freeing event, pending signal? %d, pending swap? handle=%d\n",
184963ef14f0Smrg			     __FUNCTION__, info->signal,
185063ef14f0Smrg			     info->pending.bo ? info->pending.bo->handle : 0));
185163ef14f0Smrg			assert(info->draw == &win->drawable);
185263ef14f0Smrg
185363ef14f0Smrg			if (info->pending.bo) {
185463ef14f0Smrg				if (signal) {
185563ef14f0Smrg					bool was_signalling = info->signal;
185663ef14f0Smrg					info->signal = true;
185763ef14f0Smrg					frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
185863ef14f0Smrg					info->signal = was_signalling;
185963ef14f0Smrg				}
186063ef14f0Smrg				assert(info->pending.bo->active_scanout > 0);
186163ef14f0Smrg				info->pending.bo->active_scanout--;
186263ef14f0Smrg
186363ef14f0Smrg				kgem_bo_destroy(&sna->kgem, info->pending.bo);
186463ef14f0Smrg				info->pending.bo = NULL;
186563ef14f0Smrg			}
186663ef14f0Smrg
186763ef14f0Smrg			if (info->signal && signal)
186863ef14f0Smrg				frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
186963ef14f0Smrg			info->signal = false;
187042542f5fSchristos			info->draw = NULL;
187163ef14f0Smrg			info->keepalive = 1;
187263ef14f0Smrg			assert(!info->signal);
187313496ba1Ssnj			list_del(&info->link);
187442542f5fSchristos
187542542f5fSchristos			chain = info->chain;
187642542f5fSchristos			info->chain = NULL;
187763ef14f0Smrg			info->chained = false;
187842542f5fSchristos
187942542f5fSchristos			if (!info->queued)
188013496ba1Ssnj				sna_dri2_event_free(info);
188142542f5fSchristos		}
188263ef14f0Smrg
188363ef14f0Smrg		priv->chain = NULL;
188463ef14f0Smrg	}
188563ef14f0Smrg}
188663ef14f0Smrg
188763ef14f0Smrgvoid sna_dri2_decouple_window(WindowPtr win)
188863ef14f0Smrg{
188963ef14f0Smrg	struct dri2_window *priv;
189063ef14f0Smrg
189163ef14f0Smrg	priv = dri2_window(win);
189263ef14f0Smrg	if (priv == NULL)
189363ef14f0Smrg		return;
189463ef14f0Smrg
189563ef14f0Smrg	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
189663ef14f0Smrg	decouple_window(win, priv, to_sna_from_drawable(&win->drawable), true);
189763ef14f0Smrg}
189863ef14f0Smrg
189963ef14f0Smrgvoid sna_dri2_destroy_window(WindowPtr win)
190063ef14f0Smrg{
190163ef14f0Smrg	struct dri2_window *priv;
190263ef14f0Smrg	struct sna *sna;
190363ef14f0Smrg
190463ef14f0Smrg	priv = dri2_window(win);
190563ef14f0Smrg	if (priv == NULL)
190663ef14f0Smrg		return;
190763ef14f0Smrg
190863ef14f0Smrg	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
190963ef14f0Smrg	sna = to_sna_from_drawable(&win->drawable);
191063ef14f0Smrg	decouple_window(win, priv, sna, false);
191163ef14f0Smrg
191263ef14f0Smrg	while (!list_is_empty(&priv->cache)) {
191363ef14f0Smrg		struct dri_bo *c;
191463ef14f0Smrg
191563ef14f0Smrg		c = list_first_entry(&priv->cache, struct dri_bo, link);
191663ef14f0Smrg		list_del(&c->link);
191763ef14f0Smrg
191863ef14f0Smrg		DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
191963ef14f0Smrg		assert(c->bo);
192063ef14f0Smrg		kgem_bo_destroy(&sna->kgem, c->bo);
192163ef14f0Smrg		free(c);
192242542f5fSchristos	}
192342542f5fSchristos
192442542f5fSchristos	free(priv);
192542542f5fSchristos}
192642542f5fSchristos
192742542f5fSchristosstatic void
192813496ba1Ssnjsna_dri2_flip_handler(struct drm_event_vblank *event, void *data)
192942542f5fSchristos{
193042542f5fSchristos	DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence));
193113496ba1Ssnj	sna_dri2_flip_event(data);
193242542f5fSchristos}
193342542f5fSchristos
193442542f5fSchristosstatic bool
193513496ba1Ssnjsna_dri2_flip(struct sna_dri2_event *info)
193642542f5fSchristos{
193742542f5fSchristos	struct kgem_bo *bo = get_private(info->back)->bo;
193842542f5fSchristos	struct kgem_bo *tmp_bo;
193963ef14f0Smrg	uint32_t tmp_name, tmp_flags;
194013496ba1Ssnj	int tmp_pitch;
194142542f5fSchristos
194242542f5fSchristos	DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
194342542f5fSchristos
194413496ba1Ssnj	assert(sna_pixmap_get_buffer(info->sna->front) == info->front);
194542542f5fSchristos	assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
194663ef14f0Smrg	assert(get_private(info->front)->size == get_private(info->back)->size);
194742542f5fSchristos	assert(bo->refcnt);
194842542f5fSchristos
194963ef14f0Smrg	if (info->sna->mode.flip_active) {
195063ef14f0Smrg		DBG(("%s: %d flips still active, aborting\n",
195163ef14f0Smrg		     __FUNCTION__, info->sna->mode.flip_active));
195263ef14f0Smrg		return false;
195363ef14f0Smrg	}
195463ef14f0Smrg
195563ef14f0Smrg	assert(!info->queued);
195613496ba1Ssnj	if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler,
195742542f5fSchristos			   info->type == FLIP_ASYNC ? NULL : info))
195842542f5fSchristos		return false;
195942542f5fSchristos
196063ef14f0Smrg	DBG(("%s: queued flip=%p\n", __FUNCTION__, info->type == FLIP_ASYNC ? NULL : info));
196163ef14f0Smrg	assert(info->signal || info->type != FLIP_THROTTLE);
196263ef14f0Smrg
196313496ba1Ssnj	assert(info->sna->dri2.flip_pending == NULL ||
196413496ba1Ssnj	       info->sna->dri2.flip_pending == info);
196542542f5fSchristos	if (info->type != FLIP_ASYNC)
196613496ba1Ssnj		info->sna->dri2.flip_pending = info;
196742542f5fSchristos
196842542f5fSchristos	DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
196942542f5fSchristos	     __FUNCTION__, bo->handle,
197042542f5fSchristos	     get_private(info->front)->bo->handle, info->front->name,
197142542f5fSchristos	     get_private(info->back)->bo->handle, info->back->name));
197242542f5fSchristos
197342542f5fSchristos	tmp_bo = get_private(info->front)->bo;
197442542f5fSchristos	tmp_name = info->front->name;
197513496ba1Ssnj	tmp_pitch = info->front->pitch;
197663ef14f0Smrg	tmp_flags = info->front->flags;
197763ef14f0Smrg
197863ef14f0Smrg	assert(tmp_bo->active_scanout > 0);
197963ef14f0Smrg	tmp_bo->active_scanout--;
198042542f5fSchristos
198113496ba1Ssnj	set_bo(info->sna->front, bo);
198242542f5fSchristos
198363ef14f0Smrg	info->front->flags = info->back->flags;
198442542f5fSchristos	info->front->name = info->back->name;
198513496ba1Ssnj	info->front->pitch = info->back->pitch;
198642542f5fSchristos	get_private(info->front)->bo = bo;
198763ef14f0Smrg	bo->active_scanout++;
198863ef14f0Smrg	assert(bo->active_scanout <= bo->refcnt);
198942542f5fSchristos
199063ef14f0Smrg	info->back->flags = tmp_flags;
199142542f5fSchristos	info->back->name = tmp_name;
199213496ba1Ssnj	info->back->pitch = tmp_pitch;
199342542f5fSchristos	get_private(info->back)->bo = tmp_bo;
199413496ba1Ssnj	mark_stale(info->back);
199542542f5fSchristos
199642542f5fSchristos	assert(get_private(info->front)->bo->refcnt);
199742542f5fSchristos	assert(get_private(info->back)->bo->refcnt);
199842542f5fSchristos	assert(get_private(info->front)->bo != get_private(info->back)->bo);
199942542f5fSchristos
200063ef14f0Smrg	info->keepalive = KEEPALIVE;
200142542f5fSchristos	info->queued = true;
200242542f5fSchristos	return true;
200342542f5fSchristos}
200442542f5fSchristos
200542542f5fSchristosstatic bool
200642542f5fSchristoscan_flip(struct sna * sna,
200742542f5fSchristos	 DrawablePtr draw,
200842542f5fSchristos	 DRI2BufferPtr front,
200942542f5fSchristos	 DRI2BufferPtr back,
201042542f5fSchristos	 xf86CrtcPtr crtc)
201142542f5fSchristos{
201242542f5fSchristos	WindowPtr win = (WindowPtr)draw;
201342542f5fSchristos	PixmapPtr pixmap;
201442542f5fSchristos
201542542f5fSchristos	assert((sna->flags & SNA_NO_WAIT) == 0);
201642542f5fSchristos
201742542f5fSchristos	if (!DBG_CAN_FLIP)
201842542f5fSchristos		return false;
201942542f5fSchristos
202042542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
202142542f5fSchristos		return false;
202242542f5fSchristos
202342542f5fSchristos	if (!sna->mode.front_active) {
202442542f5fSchristos		DBG(("%s: no, active CRTC\n", __FUNCTION__));
202542542f5fSchristos		return false;
202642542f5fSchristos	}
202742542f5fSchristos
202842542f5fSchristos	assert(sna->scrn->vtSema);
202963ef14f0Smrg	assert(!sna->mode.hidden);
203042542f5fSchristos
203142542f5fSchristos	if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) {
203242542f5fSchristos		DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
203342542f5fSchristos		return false;
203442542f5fSchristos	}
203542542f5fSchristos
203663ef14f0Smrg	if (front->cpp != back->cpp) {
203742542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
203863ef14f0Smrg		     __FUNCTION__, front->cpp, back->cpp));
203942542f5fSchristos		return false;
204042542f5fSchristos	}
204142542f5fSchristos
204242542f5fSchristos	if (sna->mode.shadow_active) {
204342542f5fSchristos		DBG(("%s: no, shadow enabled\n", __FUNCTION__));
204442542f5fSchristos		return false;
204542542f5fSchristos	}
204642542f5fSchristos
204742542f5fSchristos	if (!sna_crtc_is_on(crtc)) {
204863ef14f0Smrg		DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc)));
204942542f5fSchristos		return false;
205042542f5fSchristos	}
205142542f5fSchristos
205242542f5fSchristos	pixmap = get_window_pixmap(win);
205342542f5fSchristos	if (pixmap != sna->front) {
205442542f5fSchristos		DBG(("%s: no, window (pixmap=%ld) is not attached to the front buffer (pixmap=%ld)\n",
205542542f5fSchristos		     __FUNCTION__, pixmap->drawable.serialNumber, sna->front->drawable.serialNumber));
205642542f5fSchristos		return false;
205742542f5fSchristos	}
205842542f5fSchristos
205942542f5fSchristos	if (sna_pixmap_get_buffer(pixmap) != front) {
206042542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n",
206142542f5fSchristos		     __FUNCTION__, front->name,
206263ef14f0Smrg		     sna_pixmap_get_buffer(pixmap) ? sna_pixmap_get_buffer(pixmap)->name : 0,
206342542f5fSchristos		     pixmap->drawable.serialNumber));
206442542f5fSchristos		return false;
206542542f5fSchristos	}
206642542f5fSchristos
206742542f5fSchristos	assert(get_private(front)->pixmap == sna->front);
206842542f5fSchristos	assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo);
206942542f5fSchristos
207042542f5fSchristos	if (!get_private(back)->bo->scanout) {
207142542f5fSchristos		DBG(("%s: no, DRI2 drawable was too small at time of creation)\n",
207242542f5fSchristos		     __FUNCTION__));
207342542f5fSchristos		return false;
207442542f5fSchristos	}
207542542f5fSchristos
207642542f5fSchristos	if (get_private(back)->size != get_private(front)->size) {
207742542f5fSchristos		DBG(("%s: no, DRI2 drawable does not fit into scanout\n",
207842542f5fSchristos		     __FUNCTION__));
207942542f5fSchristos		return false;
208042542f5fSchristos	}
208142542f5fSchristos
208242542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
208342542f5fSchristos	     __FUNCTION__,
208442542f5fSchristos	     win->drawable.width, win->drawable.height,
208542542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
208642542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
208742542f5fSchristos	     region_num_rects(&win->clipList)));
208842542f5fSchristos	if (!RegionEqual(&win->clipList, &draw->pScreen->root->winSize)) {
208942542f5fSchristos		DBG(("%s: no, window is clipped: clip region=(%d, %d), (%d, %d), root size=(%d, %d), (%d, %d)\n",
209042542f5fSchristos		     __FUNCTION__,
209142542f5fSchristos		     win->clipList.extents.x1,
209242542f5fSchristos		     win->clipList.extents.y1,
209342542f5fSchristos		     win->clipList.extents.x2,
209442542f5fSchristos		     win->clipList.extents.y2,
209542542f5fSchristos		     draw->pScreen->root->winSize.extents.x1,
209642542f5fSchristos		     draw->pScreen->root->winSize.extents.y1,
209742542f5fSchristos		     draw->pScreen->root->winSize.extents.x2,
209842542f5fSchristos		     draw->pScreen->root->winSize.extents.y2));
209942542f5fSchristos		return false;
210042542f5fSchristos	}
210142542f5fSchristos
210242542f5fSchristos	if (draw->x != 0 || draw->y != 0 ||
210342542f5fSchristos#ifdef COMPOSITE
210442542f5fSchristos	    draw->x != pixmap->screen_x ||
210542542f5fSchristos	    draw->y != pixmap->screen_y ||
210642542f5fSchristos#endif
210742542f5fSchristos	    draw->width != pixmap->drawable.width ||
210842542f5fSchristos	    draw->height != pixmap->drawable.height) {
210942542f5fSchristos		DBG(("%s: no, window is not full size (%dx%d)!=(%dx%d)\n",
211042542f5fSchristos		     __FUNCTION__,
211142542f5fSchristos		     draw->width, draw->height,
211242542f5fSchristos		     pixmap->drawable.width,
211342542f5fSchristos		     pixmap->drawable.height));
211442542f5fSchristos		return false;
211542542f5fSchristos	}
211642542f5fSchristos
211742542f5fSchristos	/* prevent an implicit tiling mode change */
211842542f5fSchristos	if (get_private(back)->bo->tiling > I915_TILING_X) {
211942542f5fSchristos		DBG(("%s -- no, tiling mismatch: front %d, back=%d, want-tiled?=%d\n",
212042542f5fSchristos		     __FUNCTION__,
212142542f5fSchristos		     get_private(front)->bo->tiling,
212242542f5fSchristos		     get_private(back)->bo->tiling,
212342542f5fSchristos		     !!(sna->flags & SNA_LINEAR_FB)));
212442542f5fSchristos		return false;
212542542f5fSchristos	}
212642542f5fSchristos
212742542f5fSchristos	if (get_private(front)->bo->pitch != get_private(back)->bo->pitch) {
212842542f5fSchristos		DBG(("%s -- no, pitch mismatch: front %d, back=%d\n",
212942542f5fSchristos		     __FUNCTION__,
213042542f5fSchristos		     get_private(front)->bo->pitch,
213142542f5fSchristos		     get_private(back)->bo->pitch));
213242542f5fSchristos		return false;
213342542f5fSchristos	}
213442542f5fSchristos
213542542f5fSchristos	if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) {
213642542f5fSchristos		DBG(("%s -- no, pinned: front %x\n",
213742542f5fSchristos		     __FUNCTION__, sna_pixmap(pixmap)->pinned));
213842542f5fSchristos		return false;
213942542f5fSchristos	}
214042542f5fSchristos
214142542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
214242542f5fSchristos	return true;
214342542f5fSchristos}
214442542f5fSchristos
214542542f5fSchristosstatic bool
214613496ba1Ssnjcan_xchg(struct sna *sna,
214742542f5fSchristos	 DrawablePtr draw,
214842542f5fSchristos	 DRI2BufferPtr front,
214942542f5fSchristos	 DRI2BufferPtr back)
215042542f5fSchristos{
215142542f5fSchristos	WindowPtr win = (WindowPtr)draw;
215242542f5fSchristos	PixmapPtr pixmap;
215342542f5fSchristos
215442542f5fSchristos	if (!DBG_CAN_XCHG)
215542542f5fSchristos		return false;
215642542f5fSchristos
215742542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
215842542f5fSchristos		return false;
215942542f5fSchristos
216063ef14f0Smrg	if (front->cpp != back->cpp) {
216142542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
216263ef14f0Smrg		     __FUNCTION__, front->cpp, back->cpp));
216342542f5fSchristos		return false;
216442542f5fSchristos	}
216542542f5fSchristos
216642542f5fSchristos	pixmap = get_window_pixmap(win);
216742542f5fSchristos	if (get_private(front)->pixmap != pixmap) {
216842542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n",
216942542f5fSchristos		     __FUNCTION__,
217042542f5fSchristos		     get_private(front)->pixmap->drawable.serialNumber,
217142542f5fSchristos		     pixmap->drawable.serialNumber));
217242542f5fSchristos		return false;
217342542f5fSchristos	}
217442542f5fSchristos
217542542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d, pixmap size=%dx%d\n",
217642542f5fSchristos	     __FUNCTION__,
217742542f5fSchristos	     win->drawable.width, win->drawable.height,
217842542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
217942542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
218042542f5fSchristos	     region_num_rects(&win->clipList),
218142542f5fSchristos	     pixmap->drawable.width,
218242542f5fSchristos	     pixmap->drawable.height));
218342542f5fSchristos	if (is_clipped(&win->clipList, &pixmap->drawable)) {
218442542f5fSchristos		DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
218542542f5fSchristos		     __FUNCTION__,
218642542f5fSchristos		     draw->width, draw->height,
218742542f5fSchristos		     win->clipList.extents.x1,
218842542f5fSchristos		     win->clipList.extents.y1,
218942542f5fSchristos		     win->clipList.extents.x2,
219042542f5fSchristos		     win->clipList.extents.y2));
219142542f5fSchristos		return false;
219242542f5fSchristos	}
219342542f5fSchristos
219463ef14f0Smrg	DBG(("%s: back size=%x, front size=%x\n",
219563ef14f0Smrg	     __FUNCTION__, get_private(back)->size, get_private(front)->size));
219642542f5fSchristos	if (get_private(back)->size != get_private(front)->size) {
219742542f5fSchristos		DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
219842542f5fSchristos		     __FUNCTION__,
219942542f5fSchristos		     get_private(back)->size & 0x7fff, (get_private(back)->size >> 16) & 0x7fff,
220042542f5fSchristos		     get_private(front)->size & 0x7fff, (get_private(front)->size >> 16) & 0x7fff));
220142542f5fSchristos		return false;
220242542f5fSchristos	}
220342542f5fSchristos
220442542f5fSchristos	if (pixmap == sna->front && !(sna->flags & SNA_TEAR_FREE) && sna->mode.front_active) {
220542542f5fSchristos		DBG(("%s: no, front buffer, requires flipping\n",
220642542f5fSchristos		     __FUNCTION__));
220742542f5fSchristos		return false;
220842542f5fSchristos	}
220942542f5fSchristos
221042542f5fSchristos	if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) {
221142542f5fSchristos		DBG(("%s: no, pinned: %x\n",
221242542f5fSchristos		     __FUNCTION__, sna_pixmap(pixmap)->pinned));
221342542f5fSchristos		return false;
221442542f5fSchristos	}
221542542f5fSchristos
221642542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
221742542f5fSchristos	return true;
221842542f5fSchristos}
221942542f5fSchristos
222042542f5fSchristosstatic bool
222142542f5fSchristosoverlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
222242542f5fSchristos{
222342542f5fSchristos	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
222442542f5fSchristos	int c;
222542542f5fSchristos
222642542f5fSchristos	for (c = 0; c < sna->mode.num_real_crtc; c++) {
222742542f5fSchristos		xf86CrtcPtr crtc = config->crtc[c];
222842542f5fSchristos
222942542f5fSchristos		if (crtc == desired)
223042542f5fSchristos			continue;
223142542f5fSchristos
223242542f5fSchristos		if (!crtc->enabled)
223342542f5fSchristos			continue;
223442542f5fSchristos
223542542f5fSchristos		if (desired->bounds.x1 < crtc->bounds.x2 &&
223642542f5fSchristos		    desired->bounds.x2 > crtc->bounds.x1 &&
223742542f5fSchristos		    desired->bounds.y1 < crtc->bounds.y2 &&
223842542f5fSchristos		    desired->bounds.y2 > crtc->bounds.y1)
223942542f5fSchristos			return true;
224042542f5fSchristos	}
224142542f5fSchristos
224242542f5fSchristos	return false;
224342542f5fSchristos}
224442542f5fSchristos
224542542f5fSchristosstatic bool
224642542f5fSchristoscan_xchg_crtc(struct sna *sna,
224742542f5fSchristos	      DrawablePtr draw,
224863ef14f0Smrg	      xf86CrtcPtr crtc,
224942542f5fSchristos	      DRI2BufferPtr front,
225063ef14f0Smrg	      DRI2BufferPtr back)
225142542f5fSchristos{
225242542f5fSchristos	WindowPtr win = (WindowPtr)draw;
225342542f5fSchristos	PixmapPtr pixmap;
225442542f5fSchristos
225542542f5fSchristos	if (!DBG_CAN_XCHG)
225642542f5fSchristos		return false;
225742542f5fSchristos
225842542f5fSchristos	if ((sna->flags & SNA_TEAR_FREE) == 0) {
225942542f5fSchristos		DBG(("%s: no, requires TearFree\n",
226042542f5fSchristos		     __FUNCTION__));
226142542f5fSchristos		return false;
226242542f5fSchristos	}
226342542f5fSchristos
226442542f5fSchristos	if (draw->type == DRAWABLE_PIXMAP)
226542542f5fSchristos		return false;
226642542f5fSchristos
226763ef14f0Smrg	if (front->cpp != back->cpp) {
226842542f5fSchristos		DBG(("%s: no, format mismatch, front = %d, back = %d\n",
226963ef14f0Smrg		     __FUNCTION__, front->cpp, back->cpp));
227042542f5fSchristos		return false;
227142542f5fSchristos	}
227242542f5fSchristos
227342542f5fSchristos	if (memcmp(&win->clipList.extents, &crtc->bounds, sizeof(crtc->bounds))) {
227442542f5fSchristos		DBG(("%s: no, window [(%d, %d), (%d, %d)] does not cover CRTC [(%d, %d), (%d, %d)]\n",
227542542f5fSchristos		     __FUNCTION__,
227642542f5fSchristos		     win->clipList.extents.x1, win->clipList.extents.y1,
227742542f5fSchristos		     win->clipList.extents.x2, win->clipList.extents.y2,
227842542f5fSchristos		     crtc->bounds.x1, crtc->bounds.y1,
227942542f5fSchristos		     crtc->bounds.x2, crtc->bounds.y2));
228042542f5fSchristos		return false;
228142542f5fSchristos	}
228242542f5fSchristos
228342542f5fSchristos	if (sna_crtc_is_transformed(crtc)) {
228442542f5fSchristos		DBG(("%s: no, CRTC is rotated\n", __FUNCTION__));
228542542f5fSchristos		return false;
228642542f5fSchristos	}
228742542f5fSchristos
228842542f5fSchristos	pixmap = get_window_pixmap(win);
228942542f5fSchristos	if (pixmap != sna->front) {
229042542f5fSchristos		DBG(("%s: no, not attached to front buffer\n", __FUNCTION__));
229142542f5fSchristos		return false;
229242542f5fSchristos	}
229342542f5fSchristos
229442542f5fSchristos	if (get_private(front)->pixmap != pixmap) {
229542542f5fSchristos		DBG(("%s: no, DRI2 drawable is no longer attached, old pixmap=%ld, now pixmap=%ld\n",
229642542f5fSchristos		     __FUNCTION__,
229742542f5fSchristos		     get_private(front)->pixmap->drawable.serialNumber,
229842542f5fSchristos		     pixmap->drawable.serialNumber));
229942542f5fSchristos		return false;
230042542f5fSchristos	}
230142542f5fSchristos
230242542f5fSchristos	DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
230342542f5fSchristos	     __FUNCTION__,
230442542f5fSchristos	     win->drawable.width, win->drawable.height,
230542542f5fSchristos	     win->clipList.extents.x1, win->clipList.extents.y1,
230642542f5fSchristos	     win->clipList.extents.x2, win->clipList.extents.y2,
230742542f5fSchristos	     region_num_rects(&win->clipList)));
230842542f5fSchristos	if (is_clipped(&win->clipList, &win->drawable)) {
230942542f5fSchristos		DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
231042542f5fSchristos		     __FUNCTION__,
231142542f5fSchristos		     draw->width, draw->height,
231242542f5fSchristos		     win->clipList.extents.x1,
231342542f5fSchristos		     win->clipList.extents.y1,
231442542f5fSchristos		     win->clipList.extents.x2,
231542542f5fSchristos		     win->clipList.extents.y2));
231642542f5fSchristos		return false;
231742542f5fSchristos	}
231842542f5fSchristos
231942542f5fSchristos	if (overlaps_other_crtc(sna, crtc)) {
232042542f5fSchristos		DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__));
232142542f5fSchristos		return false;
232242542f5fSchristos	}
232342542f5fSchristos
232442542f5fSchristos	if (get_private(back)->size != (draw->height << 16 | draw->width)) {
232542542f5fSchristos		DBG(("%s: no, DRI2 buffers does not fit window\n",
232642542f5fSchristos		     __FUNCTION__));
232742542f5fSchristos		return false;
232842542f5fSchristos	}
232942542f5fSchristos
233042542f5fSchristos	assert(win != win->drawable.pScreen->root);
233142542f5fSchristos	DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
233242542f5fSchristos	return true;
233342542f5fSchristos}
233442542f5fSchristos
233542542f5fSchristosstatic void
233642542f5fSchristossna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
233742542f5fSchristos{
233842542f5fSchristos	WindowPtr win = (WindowPtr)draw;
233942542f5fSchristos	struct kgem_bo *back_bo, *front_bo;
234042542f5fSchristos	PixmapPtr pixmap;
234142542f5fSchristos	int tmp;
234242542f5fSchristos
234342542f5fSchristos	assert(draw->type != DRAWABLE_PIXMAP);
234442542f5fSchristos	pixmap = get_window_pixmap(win);
234542542f5fSchristos
234642542f5fSchristos	back_bo = get_private(back)->bo;
234742542f5fSchristos	front_bo = get_private(front)->bo;
234842542f5fSchristos
234963ef14f0Smrg	DBG(("%s: win=%ld, exchange front=%d/%d,ref=%d and back=%d/%d,ref=%d, pixmap=%ld %dx%d\n",
235042542f5fSchristos	     __FUNCTION__, win->drawable.id,
235163ef14f0Smrg	     front_bo->handle, front->name, get_private(front)->refcnt,
235263ef14f0Smrg	     back_bo->handle, back->name, get_private(back)->refcnt,
235342542f5fSchristos	     pixmap->drawable.serialNumber,
235442542f5fSchristos	     pixmap->drawable.width,
235542542f5fSchristos	     pixmap->drawable.height));
235642542f5fSchristos
235763ef14f0Smrg	DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
235863ef14f0Smrg	     __FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
235963ef14f0Smrg	DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
236063ef14f0Smrg	     __FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
236163ef14f0Smrg
236263ef14f0Smrg	assert(front_bo != back_bo);
236342542f5fSchristos	assert(front_bo->refcnt);
236442542f5fSchristos	assert(back_bo->refcnt);
236542542f5fSchristos
236642542f5fSchristos	assert(sna_pixmap_get_buffer(pixmap) == front);
236742542f5fSchristos
236842542f5fSchristos	assert(pixmap->drawable.height * back_bo->pitch <= kgem_bo_size(back_bo));
236942542f5fSchristos	assert(pixmap->drawable.height * front_bo->pitch <= kgem_bo_size(front_bo));
237042542f5fSchristos
237142542f5fSchristos	set_bo(pixmap, back_bo);
237242542f5fSchristos
237342542f5fSchristos	get_private(front)->bo = back_bo;
237442542f5fSchristos	get_private(back)->bo = front_bo;
237513496ba1Ssnj	mark_stale(back);
237642542f5fSchristos
237763ef14f0Smrg	assert(front_bo->active_scanout > 0);
237863ef14f0Smrg	front_bo->active_scanout--;
237963ef14f0Smrg	back_bo->active_scanout++;
238063ef14f0Smrg	assert(back_bo->active_scanout <= back_bo->refcnt);
238163ef14f0Smrg
238242542f5fSchristos	tmp = front->name;
238342542f5fSchristos	front->name = back->name;
238442542f5fSchristos	back->name = tmp;
238542542f5fSchristos
238613496ba1Ssnj	tmp = front->pitch;
238713496ba1Ssnj	front->pitch = back->pitch;
238813496ba1Ssnj	back->pitch = tmp;
238913496ba1Ssnj
239063ef14f0Smrg	tmp = front->flags;
239163ef14f0Smrg	front->flags = back->flags;
239263ef14f0Smrg	back->flags = tmp;
239363ef14f0Smrg
239442542f5fSchristos	assert(front_bo->refcnt);
239542542f5fSchristos	assert(back_bo->refcnt);
239642542f5fSchristos
239763ef14f0Smrg	assert(front_bo->pitch == get_private(front)->bo->pitch);
239863ef14f0Smrg	assert(back_bo->pitch == get_private(back)->bo->pitch);
239963ef14f0Smrg
240042542f5fSchristos	assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
240142542f5fSchristos}
240242542f5fSchristos
240342542f5fSchristosstatic void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back)
240442542f5fSchristos{
240542542f5fSchristos	WindowPtr win = (WindowPtr)draw;
240663ef14f0Smrg	struct dri2_window *priv = dri2_window(win);
240742542f5fSchristos
240842542f5fSchristos	DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n",
240942542f5fSchristos	     __FUNCTION__,
241042542f5fSchristos	     get_private(front)->bo->handle, front->name,
241142542f5fSchristos	     get_private(back)->bo->handle, back->name,
241242542f5fSchristos	     win->drawable.id,
241342542f5fSchristos	     get_window_pixmap(win)->drawable.serialNumber,
241442542f5fSchristos	     get_window_pixmap(win)->drawable.width,
241542542f5fSchristos	     get_window_pixmap(win)->drawable.height));
241663ef14f0Smrg	assert(can_xchg_crtc(sna, draw, crtc, front, back));
241742542f5fSchristos
241863ef14f0Smrg	if (APPLY_DAMAGE) {
241963ef14f0Smrg		DBG(("%s: marking drawable as damaged\n", __FUNCTION__));
242063ef14f0Smrg		sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
242163ef14f0Smrg		DamageRegionAppend(&win->drawable, &win->clipList);
242263ef14f0Smrg	}
242342542f5fSchristos	sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
242463ef14f0Smrg	if (APPLY_DAMAGE) {
242563ef14f0Smrg		sna->ignore_copy_area = false;
242663ef14f0Smrg		DamageRegionProcessPending(&win->drawable);
242763ef14f0Smrg	}
242842542f5fSchristos
242963ef14f0Smrg	if (priv->front == NULL) {
243063ef14f0Smrg		DRI2Buffer2Ptr tmp;
243142542f5fSchristos
243263ef14f0Smrg		tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
243363ef14f0Smrg		if (tmp == NULL) {
243463ef14f0Smrg			sna_shadow_unset_crtc(sna, crtc);
243563ef14f0Smrg			return;
243642542f5fSchristos		}
243742542f5fSchristos
243863ef14f0Smrg		tmp->attachment = DRI2BufferFrontLeft;
243963ef14f0Smrg		tmp->driverPrivate = tmp + 1;
244063ef14f0Smrg		tmp->cpp = back->cpp;
244163ef14f0Smrg		tmp->format = back->format;
244263ef14f0Smrg
244363ef14f0Smrg		get_private(tmp)->refcnt = 1;
244463ef14f0Smrg		get_private(tmp)->bo = kgem_create_2d(&sna->kgem,
244563ef14f0Smrg						      draw->width, draw->height, draw->bitsPerPixel,
244663ef14f0Smrg						      get_private(back)->bo->tiling,
244763ef14f0Smrg						      CREATE_SCANOUT | CREATE_EXACT);
244863ef14f0Smrg		if (get_private(tmp)->bo != NULL) {
244963ef14f0Smrg			tmp->pitch = get_private(tmp)->bo->pitch;
245063ef14f0Smrg			tmp->name = kgem_bo_flink(&sna->kgem, get_private(tmp)->bo);
245163ef14f0Smrg		}
245263ef14f0Smrg		if (tmp->name == 0) {
245363ef14f0Smrg			if (get_private(tmp)->bo != NULL)
245463ef14f0Smrg				kgem_bo_destroy(&sna->kgem, get_private(tmp)->bo);
245563ef14f0Smrg			sna_shadow_unset_crtc(sna, crtc);
245663ef14f0Smrg			return;
245763ef14f0Smrg		}
245863ef14f0Smrg		get_private(tmp)->size = get_private(back)->size;
245963ef14f0Smrg		get_private(tmp)->pixmap = get_private(front)->pixmap;
246063ef14f0Smrg		get_private(tmp)->proxy = sna_dri2_reference_buffer(front);
246163ef14f0Smrg		get_private(tmp)->bo->active_scanout++;
246242542f5fSchristos
246363ef14f0Smrg		priv->front = front = tmp;
246463ef14f0Smrg	}
246563ef14f0Smrg	assert(front == priv->front);
246642542f5fSchristos
246763ef14f0Smrg	{
246863ef14f0Smrg		struct kgem_bo *front_bo = get_private(front)->bo;
246963ef14f0Smrg		struct kgem_bo *back_bo = get_private(back)->bo;
247063ef14f0Smrg		unsigned tmp;
247142542f5fSchristos
247263ef14f0Smrg		assert(front_bo->refcnt);
247363ef14f0Smrg		assert(back_bo->refcnt);
247442542f5fSchristos
247563ef14f0Smrg		get_private(back)->bo = front_bo;
247663ef14f0Smrg		get_private(front)->bo = back_bo;
247763ef14f0Smrg		mark_stale(back);
247842542f5fSchristos
247963ef14f0Smrg		assert(front_bo->active_scanout > 0);
248063ef14f0Smrg		front_bo->active_scanout--;
248163ef14f0Smrg		back_bo->active_scanout++;
248263ef14f0Smrg		assert(back_bo->active_scanout <= back_bo->refcnt);
248342542f5fSchristos
248463ef14f0Smrg		tmp = front->name;
248563ef14f0Smrg		front->name = back->name;
248663ef14f0Smrg		back->name = tmp;
248742542f5fSchristos
248863ef14f0Smrg		tmp = front->pitch;
248963ef14f0Smrg		front->pitch = back->pitch;
249063ef14f0Smrg		back->pitch = tmp;
249142542f5fSchristos
249263ef14f0Smrg		tmp = front->flags;
249363ef14f0Smrg		front->flags = back->flags;
249463ef14f0Smrg		back->flags = tmp;
249563ef14f0Smrg	}
249642542f5fSchristos}
249742542f5fSchristos
249813496ba1Ssnjstatic void chain_swap(struct sna_dri2_event *chain)
249942542f5fSchristos{
250063ef14f0Smrg	DBG(("%s: draw=%ld, queued?=%d, type=%d\n",
250163ef14f0Smrg	     __FUNCTION__, (long)chain->draw->id, chain->queued, chain->type));
250263ef14f0Smrg
250363ef14f0Smrg	if (chain->queued) /* too early! */
250463ef14f0Smrg		return;
250542542f5fSchristos
250642542f5fSchristos	if (chain->draw == NULL) {
250713496ba1Ssnj		sna_dri2_event_free(chain);
250842542f5fSchristos		return;
250942542f5fSchristos	}
251042542f5fSchristos
251142542f5fSchristos	assert(chain == dri2_chain(chain->draw));
251263ef14f0Smrg	assert(chain->signal);
251342542f5fSchristos
251442542f5fSchristos	switch (chain->type) {
251563ef14f0Smrg	case SWAP_COMPLETE:
251642542f5fSchristos		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
251713496ba1Ssnj		if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) {
251842542f5fSchristos			sna_dri2_xchg(chain->draw, chain->front, chain->back);
251963ef14f0Smrg		} else if (can_xchg_crtc(chain->sna, chain->draw, chain->crtc,
252063ef14f0Smrg					 chain->front, chain->back)) {
252163ef14f0Smrg			sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc,
252263ef14f0Smrg					   chain->front, chain->back);
252342542f5fSchristos		} else {
252463ef14f0Smrg			__sna_dri2_copy_event(chain, chain->sync | DRI2_BO);
252542542f5fSchristos		}
252663ef14f0Smrg		assert(get_private(chain->back)->bo != get_private(chain->front)->bo);
252742542f5fSchristos	case SWAP:
252842542f5fSchristos		break;
252942542f5fSchristos	default:
253042542f5fSchristos		return;
253142542f5fSchristos	}
253242542f5fSchristos
253363ef14f0Smrg	if ((chain->type == SWAP_COMPLETE &&
253463ef14f0Smrg	     !swap_limit(chain->draw, 2 + !chain->sync) &&
253563ef14f0Smrg	     !chain->sync) ||
253663ef14f0Smrg	    !sna_next_vblank(chain)) {
253742542f5fSchristos		DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
253813496ba1Ssnj		frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
253913496ba1Ssnj		sna_dri2_event_free(chain);
254042542f5fSchristos	}
254142542f5fSchristos}
254242542f5fSchristos
254342542f5fSchristosstatic inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
254442542f5fSchristos{
254542542f5fSchristos	if (bo == NULL)
254642542f5fSchristos		return false;
254742542f5fSchristos
254863ef14f0Smrg	return __kgem_bo_is_busy(kgem, bo);
254942542f5fSchristos}
255042542f5fSchristos
255163ef14f0Smrgstatic bool sna_dri2_blit_complete(struct sna_dri2_event *info)
255242542f5fSchristos{
255363ef14f0Smrg	if (!info->bo)
255463ef14f0Smrg		return true;
255542542f5fSchristos
255663ef14f0Smrg	if (__kgem_bo_is_busy(&info->sna->kgem, info->bo)) {
255742542f5fSchristos		DBG(("%s: vsync'ed blit is still busy, postponing\n",
255842542f5fSchristos		     __FUNCTION__));
255963ef14f0Smrg		if (sna_next_vblank(info))
256042542f5fSchristos			return false;
256163ef14f0Smrg
256263ef14f0Smrg		kgem_bo_sync__gtt(&info->sna->kgem, info->bo);
256342542f5fSchristos	}
256442542f5fSchristos
256542542f5fSchristos	DBG(("%s: blit finished\n", __FUNCTION__));
256663ef14f0Smrg	kgem_bo_destroy(&info->sna->kgem, info->bo);
256763ef14f0Smrg	info->bo = NULL;
256863ef14f0Smrg
256942542f5fSchristos	return true;
257042542f5fSchristos}
257142542f5fSchristos
257213496ba1Ssnjvoid sna_dri2_vblank_handler(struct drm_event_vblank *event)
257342542f5fSchristos{
257442542f5fSchristos	struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
257513496ba1Ssnj	struct sna *sna = info->sna;
257642542f5fSchristos	DrawablePtr draw;
257742542f5fSchristos	uint64_t msc;
257842542f5fSchristos
257963ef14f0Smrg	DBG(("%s(type=%d, sequence=%d, draw=%ld)\n", __FUNCTION__, info->type, event->sequence, info->draw ? info->draw->serialNumber : 0));
258042542f5fSchristos	assert(info->queued);
258163ef14f0Smrg	info->queued = false;
258263ef14f0Smrg
258342542f5fSchristos	msc = sna_crtc_record_event(info->crtc, event);
258442542f5fSchristos
258542542f5fSchristos	draw = info->draw;
258642542f5fSchristos	if (draw == NULL) {
258742542f5fSchristos		DBG(("%s -- drawable gone\n", __FUNCTION__));
258842542f5fSchristos		goto done;
258942542f5fSchristos	}
259042542f5fSchristos
259163ef14f0Smrg	assert((info->front == NULL && info->back == NULL) || info->front != info->back);
259242542f5fSchristos	switch (info->type) {
259342542f5fSchristos	case FLIP:
259442542f5fSchristos		/* If we can still flip... */
259563ef14f0Smrg		assert(info->signal);
259642542f5fSchristos		if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
259713496ba1Ssnj		    sna_dri2_flip(info))
259842542f5fSchristos			return;
259942542f5fSchristos
260042542f5fSchristos		/* else fall through to blit */
260142542f5fSchristos	case SWAP:
260263ef14f0Smrg		assert(info->signal);
260363ef14f0Smrg		if (can_xchg(info->sna, draw, info->front, info->back)) {
260442542f5fSchristos			sna_dri2_xchg(draw, info->front, info->back);
260563ef14f0Smrg			info->type = SWAP_COMPLETE;
260663ef14f0Smrg		} else if (can_xchg_crtc(sna, draw, info->crtc,
260763ef14f0Smrg					 info->front, info->back)) {
260863ef14f0Smrg			sna_dri2_xchg_crtc(sna, draw, info->crtc,
260963ef14f0Smrg					   info->front, info->back);
261063ef14f0Smrg			info->type = SWAP_COMPLETE;
261142542f5fSchristos		}  else {
261263ef14f0Smrg			__sna_dri2_copy_event(info, DRI2_BO | DRI2_SYNC);
261363ef14f0Smrg			info->type = SWAP_COMPLETE;
261442542f5fSchristos		}
261542542f5fSchristos
261663ef14f0Smrg		if (sna_next_vblank(info))
261742542f5fSchristos			return;
261842542f5fSchristos
261942542f5fSchristos		DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
262063ef14f0Smrg		assert(info->pending.bo == NULL);
262163ef14f0Smrg		assert(info->keepalive == 1);
262242542f5fSchristos		/* fall through to SwapComplete */
262363ef14f0Smrg	case SWAP_COMPLETE:
262442542f5fSchristos		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
262542542f5fSchristos		     __FUNCTION__, info->type,
262642542f5fSchristos		     event->sequence, event->tv_sec, event->tv_usec));
262742542f5fSchristos
262863ef14f0Smrg		if (info->signal) {
262963ef14f0Smrg			if (!sna_dri2_blit_complete(info))
263042542f5fSchristos				return;
263142542f5fSchristos
263242542f5fSchristos			DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
263342542f5fSchristos			     event->sequence, event->tv_sec, event->tv_usec));
263413496ba1Ssnj			frame_swap_complete(info, DRI2_BLIT_COMPLETE);
263542542f5fSchristos		}
263663ef14f0Smrg
263763ef14f0Smrg		if (info->pending.bo) {
263863ef14f0Smrg			struct copy current_back;
263963ef14f0Smrg
264063ef14f0Smrg			DBG(("%s: swapping back handle=%d [name=%d, active=%d] for pending handle=%d [name=%d, active=%d], front handle=%d [name=%d, active=%d]\n",
264163ef14f0Smrg			     __FUNCTION__,
264263ef14f0Smrg			     get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
264363ef14f0Smrg			     info->pending.bo->handle, info->pending.name, info->pending.bo->active_scanout,
264463ef14f0Smrg			     get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
264563ef14f0Smrg
264663ef14f0Smrg			assert(info->pending.bo->active_scanout > 0);
264763ef14f0Smrg			info->pending.bo->active_scanout--;
264863ef14f0Smrg
264963ef14f0Smrg			current_back.bo = get_private(info->back)->bo;
265063ef14f0Smrg			current_back.size = get_private(info->back)->size;
265163ef14f0Smrg			current_back.name = info->back->name;
265263ef14f0Smrg			current_back.flags = info->back->flags;
265363ef14f0Smrg
265463ef14f0Smrg			get_private(info->back)->bo = info->pending.bo;
265563ef14f0Smrg			get_private(info->back)->size = info->pending.size;
265663ef14f0Smrg			info->back->name = info->pending.name;
265763ef14f0Smrg			info->back->pitch = info->pending.bo->pitch;
265863ef14f0Smrg			info->back->flags = info->pending.flags;
265963ef14f0Smrg			info->pending.bo = NULL;
266063ef14f0Smrg
266163ef14f0Smrg			assert(get_private(info->back)->bo != get_private(info->front)->bo);
266263ef14f0Smrg
266363ef14f0Smrg			if (can_xchg(info->sna, info->draw, info->front, info->back))
266463ef14f0Smrg				sna_dri2_xchg(info->draw, info->front, info->back);
266563ef14f0Smrg			else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
266663ef14f0Smrg						 info->front, info->back))
266763ef14f0Smrg				sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
266863ef14f0Smrg						   info->front, info->back);
266963ef14f0Smrg			else
267063ef14f0Smrg				__sna_dri2_copy_event(info, info->sync | DRI2_BO);
267163ef14f0Smrg
267263ef14f0Smrg			sna_dri2_cache_bo(info->sna, info->draw,
267363ef14f0Smrg					  get_private(info->back)->bo,
267463ef14f0Smrg					  info->back->name,
267563ef14f0Smrg					  get_private(info->back)->size,
267663ef14f0Smrg					  info->back->flags);
267763ef14f0Smrg
267863ef14f0Smrg			get_private(info->back)->bo = current_back.bo;
267963ef14f0Smrg			get_private(info->back)->size = current_back.size;
268063ef14f0Smrg			info->back->name = current_back.name;
268163ef14f0Smrg			info->back->pitch = current_back.bo->pitch;
268263ef14f0Smrg			info->back->flags = current_back.flags;
268363ef14f0Smrg
268463ef14f0Smrg			DBG(("%s: restored current back handle=%d [name=%d, active=%d], active=%d], front handle=%d [name=%d, active=%d]\n",
268563ef14f0Smrg			     __FUNCTION__,
268663ef14f0Smrg			     get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
268763ef14f0Smrg			     get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
268863ef14f0Smrg
268963ef14f0Smrg			assert(info->draw);
269063ef14f0Smrg			assert(!info->signal);
269163ef14f0Smrg			info->keepalive++;
269263ef14f0Smrg			info->signal = true;
269363ef14f0Smrg		}
269463ef14f0Smrg
269563ef14f0Smrg		if (--info->keepalive) {
269663ef14f0Smrg			if (sna_next_vblank(info))
269763ef14f0Smrg				return;
269863ef14f0Smrg
269963ef14f0Smrg			if (info->signal) {
270063ef14f0Smrg				DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
270163ef14f0Smrg				     event->sequence, event->tv_sec, event->tv_usec));
270263ef14f0Smrg				frame_swap_complete(info, DRI2_BLIT_COMPLETE);
270363ef14f0Smrg			}
270463ef14f0Smrg		}
270542542f5fSchristos		break;
270642542f5fSchristos
270742542f5fSchristos	case WAITMSC:
270842542f5fSchristos		assert(info->client);
270942542f5fSchristos		DRI2WaitMSCComplete(info->client, draw, msc,
271042542f5fSchristos				    event->tv_sec, event->tv_usec);
271142542f5fSchristos		break;
271242542f5fSchristos	default:
271342542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
271442542f5fSchristos			   "%s: unknown vblank event received\n", __func__);
271542542f5fSchristos		/* Unknown type */
271642542f5fSchristos		break;
271742542f5fSchristos	}
271842542f5fSchristos
271942542f5fSchristos	if (info->chain) {
272063ef14f0Smrg		DBG(("%s: continuing chain\n", __FUNCTION__));
272142542f5fSchristos		assert(info->chain != info);
272242542f5fSchristos		assert(info->draw == draw);
272363ef14f0Smrg		sna_dri2_remove_event(info);
272413496ba1Ssnj		chain_swap(info->chain);
272542542f5fSchristos	}
272642542f5fSchristos
272742542f5fSchristosdone:
272813496ba1Ssnj	sna_dri2_event_free(info);
272942542f5fSchristos	DBG(("%s complete\n", __FUNCTION__));
273042542f5fSchristos}
273142542f5fSchristos
273263ef14f0Smrgstatic void
273342542f5fSchristossna_dri2_immediate_blit(struct sna *sna,
273442542f5fSchristos			struct sna_dri2_event *info,
273563ef14f0Smrg			bool sync)
273642542f5fSchristos{
273763ef14f0Smrg	struct sna_dri2_event *chain = dri2_chain(info->draw);
273842542f5fSchristos
273942542f5fSchristos	if (sna->flags & SNA_NO_WAIT)
274042542f5fSchristos		sync = false;
274142542f5fSchristos
274263ef14f0Smrg	DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, pipe %d\n",
274363ef14f0Smrg	     __FUNCTION__, sync, chain != info, info->pipe));
274463ef14f0Smrg	assert(chain);
274542542f5fSchristos
274663ef14f0Smrg	info->type = SWAP_COMPLETE;
274763ef14f0Smrg	info->sync = sync;
274863ef14f0Smrg	info->keepalive = KEEPALIVE;
274942542f5fSchristos
275063ef14f0Smrg	if (chain == info) {
275163ef14f0Smrg		DBG(("%s: no pending blit, starting chain\n", __FUNCTION__));
275263ef14f0Smrg
275363ef14f0Smrg		assert(info->front != info->back);
275463ef14f0Smrg		if (can_xchg(info->sna, info->draw, info->front, info->back)) {
275563ef14f0Smrg			sna_dri2_xchg(info->draw, info->front, info->back);
275663ef14f0Smrg		} else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
275763ef14f0Smrg					 info->front, info->back)) {
275863ef14f0Smrg			sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
275963ef14f0Smrg					   info->front, info->back);
276063ef14f0Smrg		} else
276163ef14f0Smrg			__sna_dri2_copy_event(info, sync | DRI2_BO);
276263ef14f0Smrg
276363ef14f0Smrg		assert(info->signal);
276463ef14f0Smrg
276563ef14f0Smrg		if ((!swap_limit(info->draw, 2 + !sync) && !sync) ||
276663ef14f0Smrg		    !sna_next_vblank(info)) {
276763ef14f0Smrg			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
276863ef14f0Smrg			frame_swap_complete(info, DRI2_BLIT_COMPLETE);
276963ef14f0Smrg			sna_dri2_event_free(info);
277063ef14f0Smrg		}
277163ef14f0Smrg		return;
277263ef14f0Smrg	}
277363ef14f0Smrg
277463ef14f0Smrg	DBG(("%s: current event front=%d [name=%d, active?=%d], back=%d [name=%d, active?=%d]\n", __FUNCTION__,
277563ef14f0Smrg	     get_private(chain->front)->bo->handle, chain->front->name, get_private(chain->front)->bo->active_scanout,
277663ef14f0Smrg	     get_private(chain->back)->bo->handle, chain->back->name, get_private(chain->back)->bo->active_scanout));
277763ef14f0Smrg
277863ef14f0Smrg	if (chain->type == SWAP_COMPLETE && chain->front == info->front) {
277963ef14f0Smrg		assert(chain->draw == info->draw);
278063ef14f0Smrg		assert(chain->client == info->client);
278163ef14f0Smrg		assert(chain->event_complete == info->event_complete);
278263ef14f0Smrg		assert(chain->event_data == info->event_data);
278363ef14f0Smrg		assert(chain->queued);
278463ef14f0Smrg
278563ef14f0Smrg		if ((!sync || !chain->sync) && chain->pending.bo) {
278663ef14f0Smrg			bool signal = chain->signal;
278763ef14f0Smrg
278863ef14f0Smrg			DBG(("%s: swap elision, unblocking client\n", __FUNCTION__));
278963ef14f0Smrg			assert(chain->draw);
279063ef14f0Smrg			chain->signal = true;
279163ef14f0Smrg			frame_swap_complete(chain, DRI2_EXCHANGE_COMPLETE);
279263ef14f0Smrg			chain->signal = signal;
279363ef14f0Smrg
279463ef14f0Smrg			assert(chain->pending.bo->active_scanout > 0);
279563ef14f0Smrg			chain->pending.bo->active_scanout--;
279663ef14f0Smrg
279763ef14f0Smrg			sna_dri2_cache_bo(chain->sna, chain->draw,
279863ef14f0Smrg					  chain->pending.bo,
279963ef14f0Smrg					  chain->pending.name,
280063ef14f0Smrg					  chain->pending.size,
280163ef14f0Smrg					  chain->pending.flags);
280263ef14f0Smrg			chain->pending.bo = NULL;
280363ef14f0Smrg		}
280463ef14f0Smrg
280563ef14f0Smrg		if (chain->pending.bo == NULL && swap_limit(info->draw, 2 + !sync)) {
280663ef14f0Smrg			DBG(("%s: setting handle=%d as pending blit (current event front=%d, back=%d)\n", __FUNCTION__,
280763ef14f0Smrg			     get_private(info->back)->bo->handle,
280863ef14f0Smrg			     get_private(chain->front)->bo->handle,
280963ef14f0Smrg			     get_private(chain->back)->bo->handle));
281063ef14f0Smrg			chain->pending.bo = ref(get_private(info->back)->bo);
281163ef14f0Smrg			chain->pending.size = get_private(info->back)->size;
281263ef14f0Smrg			chain->pending.name = info->back->name;
281363ef14f0Smrg			chain->pending.flags = info->back->flags;
281463ef14f0Smrg			chain->sync = sync;
281563ef14f0Smrg			info->signal = false; /* transfer signal to pending */
281663ef14f0Smrg
281763ef14f0Smrg			/* Prevent us from handing it back on next GetBuffers */
281863ef14f0Smrg			chain->pending.bo->active_scanout++;
281963ef14f0Smrg
282063ef14f0Smrg			sna_dri2_event_free(info);
282163ef14f0Smrg			return;
282242542f5fSchristos		}
282342542f5fSchristos	}
282442542f5fSchristos
282563ef14f0Smrg	DBG(("%s: pending blit, chained\n", __FUNCTION__));
282642542f5fSchristos}
282742542f5fSchristos
282842542f5fSchristosstatic bool
282913496ba1Ssnjsna_dri2_flip_continue(struct sna_dri2_event *info)
283042542f5fSchristos{
283163ef14f0Smrg	struct kgem_bo *bo = get_private(info->front)->bo;
283242542f5fSchristos
283363ef14f0Smrg	DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue));
283463ef14f0Smrg	assert(info->flip_continue > 0);
283563ef14f0Smrg	info->type = info->flip_continue;
283663ef14f0Smrg	info->flip_continue = 0;
283742542f5fSchristos
283863ef14f0Smrg	assert(!info->signal);
283963ef14f0Smrg	info->signal = info->type == FLIP_THROTTLE && info->draw;
284042542f5fSchristos
284163ef14f0Smrg	if (info->sna->mode.front_active == 0)
284263ef14f0Smrg		return false;
284342542f5fSchristos
284463ef14f0Smrg	if (bo != sna_pixmap(info->sna->front)->gpu_bo)
284563ef14f0Smrg		return false;
284642542f5fSchristos
284763ef14f0Smrg	assert(!info->queued);
284863ef14f0Smrg	if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
284963ef14f0Smrg		return false;
285042542f5fSchristos
285163ef14f0Smrg	DBG(("%s: queued flip=%p\n", __FUNCTION__, info));
285263ef14f0Smrg	assert(info->sna->dri2.flip_pending == NULL ||
285363ef14f0Smrg	       info->sna->dri2.flip_pending == info);
285463ef14f0Smrg	info->sna->dri2.flip_pending = info;
285563ef14f0Smrg	info->queued = true;
285642542f5fSchristos
285763ef14f0Smrg	return true;
285863ef14f0Smrg}
285942542f5fSchristos
286063ef14f0Smrgstatic bool
286163ef14f0Smrgsna_dri2_flip_keepalive(struct sna_dri2_event *info)
286263ef14f0Smrg{
286363ef14f0Smrg	DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1));
286463ef14f0Smrg	assert(info->keepalive > 0);
286563ef14f0Smrg	if (!--info->keepalive)
286663ef14f0Smrg		return false;
286742542f5fSchristos
286863ef14f0Smrg	if (info->draw == NULL)
286963ef14f0Smrg		return false;
287042542f5fSchristos
287163ef14f0Smrg	DBG(("%s: marking next flip as complete\n", __FUNCTION__));
287263ef14f0Smrg	info->flip_continue = FLIP_COMPLETE;
287363ef14f0Smrg	return sna_dri2_flip_continue(info);
287442542f5fSchristos}
287542542f5fSchristos
287642542f5fSchristosstatic void chain_flip(struct sna *sna)
287742542f5fSchristos{
287842542f5fSchristos	struct sna_dri2_event *chain = sna->dri2.flip_pending;
287942542f5fSchristos
288042542f5fSchristos	assert(chain->type == FLIP);
288163ef14f0Smrg	DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n",
288263ef14f0Smrg	     __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0));
288342542f5fSchristos
288442542f5fSchristos	sna->dri2.flip_pending = NULL;
288542542f5fSchristos	if (chain->draw == NULL) {
288613496ba1Ssnj		sna_dri2_event_free(chain);
288742542f5fSchristos		return;
288842542f5fSchristos	}
288942542f5fSchristos
289042542f5fSchristos	assert(chain == dri2_chain(chain->draw));
289142542f5fSchristos	assert(!chain->queued);
289242542f5fSchristos
289342542f5fSchristos	if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
289413496ba1Ssnj	    sna_dri2_flip(chain)) {
289542542f5fSchristos		DBG(("%s: performing chained flip\n", __FUNCTION__));
289642542f5fSchristos	} else {
289742542f5fSchristos		DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
289863ef14f0Smrg		__sna_dri2_copy_event(chain, DRI2_SYNC);
289942542f5fSchristos
290013496ba1Ssnj		if (xorg_can_triple_buffer()) {
290163ef14f0Smrg			chain->type = SWAP_COMPLETE;
290263ef14f0Smrg			assert(chain->signal);
290363ef14f0Smrg			if (sna_next_vblank(chain))
290442542f5fSchristos				return;
290542542f5fSchristos		}
290642542f5fSchristos
290742542f5fSchristos		DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__));
290813496ba1Ssnj		frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
290913496ba1Ssnj		sna_dri2_event_free(chain);
291042542f5fSchristos	}
291142542f5fSchristos}
291242542f5fSchristos
291313496ba1Ssnjstatic void sna_dri2_flip_event(struct sna_dri2_event *flip)
291442542f5fSchristos{
291513496ba1Ssnj	struct sna *sna = flip->sna;
291613496ba1Ssnj
291763ef14f0Smrg	DBG(("%s flip=%p (pipe=%d, event=%d, queued?=%d)\n", __FUNCTION__, flip, flip->pipe, flip->type, flip->queued));
291863ef14f0Smrg	if (!flip->queued) /* pageflip died whilst being queued */
291963ef14f0Smrg		return;
292063ef14f0Smrg	flip->queued = false;
292142542f5fSchristos
292242542f5fSchristos	if (sna->dri2.flip_pending == flip)
292342542f5fSchristos		sna->dri2.flip_pending = NULL;
292442542f5fSchristos
292542542f5fSchristos	/* We assume our flips arrive in order, so we don't check the frame */
292642542f5fSchristos	switch (flip->type) {
292742542f5fSchristos	case FLIP:
292863ef14f0Smrg		if (flip->signal) {
292963ef14f0Smrg			DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
293063ef14f0Smrg			frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
293163ef14f0Smrg		}
293213496ba1Ssnj		sna_dri2_event_free(flip);
293342542f5fSchristos
293442542f5fSchristos		if (sna->dri2.flip_pending)
293542542f5fSchristos			chain_flip(sna);
293642542f5fSchristos		break;
293742542f5fSchristos
293842542f5fSchristos	case FLIP_THROTTLE:
293963ef14f0Smrg		if (flip->signal) {
294063ef14f0Smrg			DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
294163ef14f0Smrg			frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
294263ef14f0Smrg		}
294342542f5fSchristos	case FLIP_COMPLETE:
294463ef14f0Smrg		assert(!flip->signal);
294542542f5fSchristos		if (sna->dri2.flip_pending) {
294663ef14f0Smrg			DBG(("%s: pending flip\n", __FUNCTION__));
294713496ba1Ssnj			sna_dri2_event_free(flip);
294842542f5fSchristos			chain_flip(sna);
294963ef14f0Smrg		} else if (!flip->flip_continue) {
295042542f5fSchristos			DBG(("%s: flip chain complete\n", __FUNCTION__));
295163ef14f0Smrg			if (!sna_dri2_flip_keepalive(flip)) {
295263ef14f0Smrg				if (flip->chain) {
295363ef14f0Smrg					sna_dri2_remove_event(flip);
295463ef14f0Smrg					chain_swap(flip->chain);
295563ef14f0Smrg				}
295642542f5fSchristos
295763ef14f0Smrg				sna_dri2_event_free(flip);
295842542f5fSchristos			}
295913496ba1Ssnj		} else if (!sna_dri2_flip_continue(flip)) {
296042542f5fSchristos			DBG(("%s: no longer able to flip\n", __FUNCTION__));
296163ef14f0Smrg			if (flip->draw != NULL)
296263ef14f0Smrg				__sna_dri2_copy_event(flip, 0);
296363ef14f0Smrg			if (flip->signal) {
296463ef14f0Smrg				DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
296563ef14f0Smrg				frame_swap_complete(flip, DRI2_BLIT_COMPLETE);
296663ef14f0Smrg			}
296763ef14f0Smrg			sna_dri2_event_free(flip);
296842542f5fSchristos		}
296942542f5fSchristos		break;
297042542f5fSchristos
297142542f5fSchristos	default: /* Unknown type */
297242542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
297342542f5fSchristos			   "%s: unknown vblank event received\n", __func__);
297413496ba1Ssnj		sna_dri2_event_free(flip);
297542542f5fSchristos		if (sna->dri2.flip_pending)
297642542f5fSchristos			chain_flip(sna);
297742542f5fSchristos		break;
297842542f5fSchristos	}
297942542f5fSchristos}
298042542f5fSchristos
298163ef14f0Smrgstatic int
298263ef14f0Smrgsna_query_vblank(struct sna *sna, xf86CrtcPtr crtc, union drm_wait_vblank *vbl)
298363ef14f0Smrg{
298463ef14f0Smrg	VG_CLEAR(*vbl);
298563ef14f0Smrg	vbl->request.type =
298663ef14f0Smrg		_DRM_VBLANK_RELATIVE | pipe_select(sna_crtc_pipe(crtc));
298763ef14f0Smrg	vbl->request.sequence = 0;
298863ef14f0Smrg
298963ef14f0Smrg	return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
299063ef14f0Smrg}
299163ef14f0Smrg
299242542f5fSchristosstatic uint64_t
299342542f5fSchristosget_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
299442542f5fSchristos{
299542542f5fSchristos	union drm_wait_vblank vbl;
299663ef14f0Smrg	uint64_t ret;
299742542f5fSchristos
299863ef14f0Smrg	if (sna_query_vblank(sna, crtc, &vbl) == 0)
299942542f5fSchristos		ret = sna_crtc_record_vblank(crtc, &vbl);
300063ef14f0Smrg	else
300163ef14f0Smrg		ret = sna_crtc_last_swap(crtc)->msc;
300242542f5fSchristos
300342542f5fSchristos	return draw_current_msc(draw, crtc, ret);
300442542f5fSchristos}
300542542f5fSchristos
300642542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR)
300742542f5fSchristosstatic Bool find(pointer value, XID id, pointer cdata)
300842542f5fSchristos{
300942542f5fSchristos	return TRUE;
301042542f5fSchristos}
301142542f5fSchristos#endif
301242542f5fSchristos
301342542f5fSchristosstatic int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
301442542f5fSchristos{
301542542f5fSchristos	if ((sna->flags & SNA_TRIPLE_BUFFER) == 0) {
301642542f5fSchristos		DBG(("%s: triple buffer disabled, using FLIP\n", __FUNCTION__));
301742542f5fSchristos		return FLIP;
301842542f5fSchristos	}
301942542f5fSchristos
302042542f5fSchristos	if (async) {
302142542f5fSchristos		DBG(("%s: running async, using %s\n", __FUNCTION__,
302242542f5fSchristos		     sna->flags & SNA_HAS_ASYNC_FLIP ? "FLIP_ASYNC" : "FLIP_COMPLETE"));
302342542f5fSchristos		return sna->flags & SNA_HAS_ASYNC_FLIP ? FLIP_ASYNC : FLIP_COMPLETE;
302442542f5fSchristos	}
302542542f5fSchristos
302613496ba1Ssnj	if (xorg_can_triple_buffer()) {
302742542f5fSchristos		DBG(("%s: triple buffer enabled, using FLIP_THROTTLE\n", __FUNCTION__));
302842542f5fSchristos		return FLIP_THROTTLE;
302942542f5fSchristos	}
303042542f5fSchristos
303142542f5fSchristos#if defined(CHECK_FOR_COMPOSITOR)
303242542f5fSchristos	/* Hack: Disable triple buffering for compositors */
303342542f5fSchristos	{
303442542f5fSchristos		struct sna_client *priv = sna_client(client);
303542542f5fSchristos		if (priv->is_compositor == 0)
303642542f5fSchristos			priv->is_compositor =
303742542f5fSchristos				LookupClientResourceComplex(client,
303842542f5fSchristos							    CompositeClientWindowType+1,
303942542f5fSchristos							    find, NULL) ? FLIP : FLIP_COMPLETE;
304042542f5fSchristos
304142542f5fSchristos		DBG(("%s: fake triple buffer enabled?=%d using %s\n", __FUNCTION__,
304242542f5fSchristos		     priv->is_compositor != FLIP, priv->is_compositor == FLIP ? "FLIP" : "FLIP_COMPLETE"));
304342542f5fSchristos		return priv->is_compositor;
304442542f5fSchristos	}
304542542f5fSchristos#else
304642542f5fSchristos	DBG(("%s: fake triple buffer enabled, using FLIP_COMPLETE\n", __FUNCTION__));
304742542f5fSchristos	return FLIP_COMPLETE;
304842542f5fSchristos#endif
304942542f5fSchristos}
305042542f5fSchristos
305142542f5fSchristosstatic bool immediate_swap(struct sna *sna,
305242542f5fSchristos			   DrawablePtr draw,
305342542f5fSchristos			   xf86CrtcPtr crtc,
305463ef14f0Smrg			   uint64_t *target_msc,
305563ef14f0Smrg			   uint64_t divisor,
305663ef14f0Smrg			   uint64_t remainder,
305742542f5fSchristos			   uint64_t *current_msc)
305842542f5fSchristos{
305963ef14f0Smrg	/*
306063ef14f0Smrg	 * If divisor is zero, or current_msc is smaller than target_msc
306163ef14f0Smrg	 * we just need to make sure target_msc passes before initiating
306263ef14f0Smrg	 * the swap.
306363ef14f0Smrg	 */
306442542f5fSchristos	if (divisor == 0) {
306542542f5fSchristos		*current_msc = -1;
306642542f5fSchristos
306742542f5fSchristos		if (sna->flags & SNA_NO_WAIT) {
306842542f5fSchristos			DBG(("%s: yes, waits are disabled\n", __FUNCTION__));
306942542f5fSchristos			return true;
307042542f5fSchristos		}
307142542f5fSchristos
307263ef14f0Smrg		if (*target_msc)
307342542f5fSchristos			*current_msc = get_current_msc(sna, draw, crtc);
307442542f5fSchristos
307542542f5fSchristos		DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
307663ef14f0Smrg		     __FUNCTION__, (long)*current_msc, (long)*target_msc,
307763ef14f0Smrg		     (*current_msc >= *target_msc - 1) ? "yes" : "no"));
307863ef14f0Smrg		return *current_msc >= *target_msc - 1;
307942542f5fSchristos	}
308042542f5fSchristos
308142542f5fSchristos	DBG(("%s: explicit waits requests, divisor=%ld\n",
308242542f5fSchristos	     __FUNCTION__, (long)divisor));
308342542f5fSchristos	*current_msc = get_current_msc(sna, draw, crtc);
308463ef14f0Smrg	if (*current_msc >= *target_msc) {
308563ef14f0Smrg		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
308663ef14f0Smrg		     __FUNCTION__,
308763ef14f0Smrg		     (long long)*current_msc,
308863ef14f0Smrg		     (long long)*target_msc,
308963ef14f0Smrg		     (long long)divisor,
309063ef14f0Smrg		     (long long)remainder));
309163ef14f0Smrg
309263ef14f0Smrg		*target_msc = *current_msc + remainder - *current_msc % divisor;
309363ef14f0Smrg		if (*target_msc <= *current_msc)
309463ef14f0Smrg			*target_msc += divisor;
309563ef14f0Smrg	}
309663ef14f0Smrg
309763ef14f0Smrg	DBG(("%s: target_msc=%lld, current_msc=%lld, immediate?=%d\n",
309863ef14f0Smrg	     __FUNCTION__, (long long)*target_msc, (long long)*current_msc,
309963ef14f0Smrg	     *current_msc >= *target_msc - 1));
310063ef14f0Smrg	return *current_msc >= *target_msc - 1;
310142542f5fSchristos}
310242542f5fSchristos
310342542f5fSchristosstatic bool
310442542f5fSchristossna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
310542542f5fSchristos		       DRI2BufferPtr front, DRI2BufferPtr back,
310663ef14f0Smrg		       bool immediate, CARD64 *target_msc, CARD64 current_msc,
310742542f5fSchristos		       DRI2SwapEventPtr func, void *data)
310842542f5fSchristos{
310942542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
311042542f5fSchristos	struct sna_dri2_event *info;
311142542f5fSchristos
311263ef14f0Smrg	if (immediate) {
311363ef14f0Smrg		bool signal = false;
311442542f5fSchristos		info = sna->dri2.flip_pending;
311542542f5fSchristos		DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
311663ef14f0Smrg		     __FUNCTION__, sna_crtc_pipe(crtc),
311763ef14f0Smrg		     info != NULL, info ? info->flip_continue : 0,
311842542f5fSchristos		     info && info->draw == draw));
311942542f5fSchristos
312042542f5fSchristos		if (info && info->draw == draw) {
312142542f5fSchristos			assert(info->type != FLIP);
312263ef14f0Smrg			assert(info->queued);
312363ef14f0Smrg			assert(info->front != info->back);
312463ef14f0Smrg			if (info->front != front) {
312563ef14f0Smrg				assert(info->front != NULL);
312663ef14f0Smrg				_sna_dri2_destroy_buffer(sna, draw, info->front);
312763ef14f0Smrg				info->front = sna_dri2_reference_buffer(front);
312863ef14f0Smrg			}
312942542f5fSchristos			if (info->back != back) {
313063ef14f0Smrg				assert(info->back != NULL);
313163ef14f0Smrg				_sna_dri2_destroy_buffer(sna, draw, info->back);
313242542f5fSchristos				info->back = sna_dri2_reference_buffer(back);
313342542f5fSchristos			}
313463ef14f0Smrg			assert(info->front != info->back);
313563ef14f0Smrg			DBG(("%s: executing xchg of pending flip: flip_continue=%d, keepalive=%d, chain?=%d\n", __FUNCTION__, info->flip_continue, info->keepalive, current_msc < *target_msc));
313663ef14f0Smrg			sna_dri2_xchg(draw, front, back);
313763ef14f0Smrg			info->keepalive = KEEPALIVE;
313863ef14f0Smrg			if (xorg_can_triple_buffer() &&
313963ef14f0Smrg			    current_msc < *target_msc) {
314042542f5fSchristos				DBG(("%s: chaining flip\n", __FUNCTION__));
314163ef14f0Smrg				info->flip_continue = FLIP_THROTTLE;
314242542f5fSchristos				goto out;
314363ef14f0Smrg			} else {
314463ef14f0Smrg				info->flip_continue = FLIP_COMPLETE;
314563ef14f0Smrg				signal = info->signal;
314663ef14f0Smrg				assert(info->draw);
314763ef14f0Smrg				info->signal = true;
314863ef14f0Smrg				goto new_back;
314942542f5fSchristos			}
315042542f5fSchristos		}
315142542f5fSchristos
315263ef14f0Smrg		info = sna_dri2_add_event(sna, draw, client, crtc);
315342542f5fSchristos		if (info == NULL)
315442542f5fSchristos			return false;
315542542f5fSchristos
315642542f5fSchristos		assert(info->crtc == crtc);
315742542f5fSchristos		info->event_complete = func;
315842542f5fSchristos		info->event_data = data;
315963ef14f0Smrg		assert(info->draw);
316063ef14f0Smrg		info->signal = true;
316142542f5fSchristos
316263ef14f0Smrg		assert(front != back);
316342542f5fSchristos		info->front = sna_dri2_reference_buffer(front);
316442542f5fSchristos		info->back = sna_dri2_reference_buffer(back);
316542542f5fSchristos
316642542f5fSchristos		if (sna->dri2.flip_pending) {
316742542f5fSchristos			/* We need to first wait (one vblank) for the
316842542f5fSchristos			 * async flips to complete before this client
316942542f5fSchristos			 * can take over.
317042542f5fSchristos			 */
317142542f5fSchristos			DBG(("%s: queueing flip after pending completion\n",
317242542f5fSchristos			     __FUNCTION__));
317363ef14f0Smrg			info->type = FLIP;
317442542f5fSchristos			sna->dri2.flip_pending = info;
317542542f5fSchristos			current_msc++;
317663ef14f0Smrg		} else if (sna->mode.flip_active) {
317763ef14f0Smrg			DBG(("%s: %d outstanding flips from old client, queueing\n",
317863ef14f0Smrg			     __FUNCTION__, sna->mode.flip_active));
317963ef14f0Smrg			goto queue;
318042542f5fSchristos		} else {
318163ef14f0Smrg			info->type = use_triple_buffer(sna, client, *target_msc == 0);
318213496ba1Ssnj			if (!sna_dri2_flip(info)) {
318342542f5fSchristos				DBG(("%s: flip failed, falling back\n", __FUNCTION__));
318463ef14f0Smrg				info->signal = false;
318513496ba1Ssnj				sna_dri2_event_free(info);
318642542f5fSchristos				return false;
318742542f5fSchristos			}
318863ef14f0Smrg			assert(get_private(info->front)->bo->active_scanout);
318942542f5fSchristos		}
319042542f5fSchristos
319163ef14f0Smrg		swap_limit(draw, 1 + (info->type == FLIP_THROTTLE));
319263ef14f0Smrg		if (info->type >= FLIP_COMPLETE) {
319342542f5fSchristosnew_back:
319413496ba1Ssnj			if (!xorg_can_triple_buffer())
319563ef14f0Smrg				sna_dri2_get_back(sna, draw, back);
319642542f5fSchristos			DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
319713496ba1Ssnj			frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
319863ef14f0Smrg			assert(info->draw);
319963ef14f0Smrg			info->signal = signal;
320042542f5fSchristos			if (info->type == FLIP_ASYNC)
320113496ba1Ssnj				sna_dri2_event_free(info);
320242542f5fSchristos		}
320342542f5fSchristosout:
320442542f5fSchristos		DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1));
320542542f5fSchristos		*target_msc = current_msc + 1;
320642542f5fSchristos		return true;
320742542f5fSchristos	}
320842542f5fSchristos
320963ef14f0Smrgqueue:
321063ef14f0Smrg	if (KEEPALIVE > 1 && sna->dri2.flip_pending) {
321163ef14f0Smrg		info = sna->dri2.flip_pending;
321263ef14f0Smrg		info->keepalive = 1;
321363ef14f0Smrg	}
321463ef14f0Smrg
321563ef14f0Smrg	info = sna_dri2_add_event(sna, draw, client, crtc);
321642542f5fSchristos	if (info == NULL)
321742542f5fSchristos		return false;
321842542f5fSchristos
321942542f5fSchristos	assert(info->crtc == crtc);
322042542f5fSchristos	info->event_complete = func;
322142542f5fSchristos	info->event_data = data;
322263ef14f0Smrg	assert(info->draw);
322363ef14f0Smrg	info->signal = true;
322442542f5fSchristos	info->type = FLIP;
322542542f5fSchristos
322663ef14f0Smrg	assert(front != back);
322742542f5fSchristos	info->front = sna_dri2_reference_buffer(front);
322842542f5fSchristos	info->back = sna_dri2_reference_buffer(back);
322942542f5fSchristos
323063ef14f0Smrg	if (*target_msc <= current_msc + 1 && sna_dri2_flip(info)) {
323142542f5fSchristos		*target_msc = current_msc + 1;
323242542f5fSchristos	} else {
323342542f5fSchristos		/* Account for 1 frame extra pageflip delay */
323463ef14f0Smrg		if (!sna_wait_vblank(info,
323563ef14f0Smrg				     draw_target_seq(draw, *target_msc - 1))) {
323663ef14f0Smrg			info->signal = false;
323713496ba1Ssnj			sna_dri2_event_free(info);
323842542f5fSchristos			return false;
323942542f5fSchristos		}
324042542f5fSchristos	}
324142542f5fSchristos
324242542f5fSchristos	DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
324342542f5fSchristos	swap_limit(draw, 1);
324442542f5fSchristos	return true;
324542542f5fSchristos}
324642542f5fSchristos
324742542f5fSchristosstatic bool has_pending_events(struct sna *sna)
324842542f5fSchristos{
324942542f5fSchristos	struct pollfd pfd;
325042542f5fSchristos	pfd.fd = sna->kgem.fd;
325142542f5fSchristos	pfd.events = POLLIN;
325242542f5fSchristos	return poll(&pfd, 1, 0) == 1;
325342542f5fSchristos}
325442542f5fSchristos
325542542f5fSchristos/*
325642542f5fSchristos * ScheduleSwap is responsible for requesting a DRM vblank event for the
325742542f5fSchristos * appropriate frame.
325842542f5fSchristos *
325942542f5fSchristos * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
326042542f5fSchristos * the vblank requested can simply be the last queued swap frame + the swap
326142542f5fSchristos * interval for the drawable.
326242542f5fSchristos *
326342542f5fSchristos * In the case of a page flip, we request an event for the last queued swap
326442542f5fSchristos * frame + swap interval - 1, since we'll need to queue the flip for the frame
326542542f5fSchristos * immediately following the received event.
326642542f5fSchristos *
326742542f5fSchristos * The client will be blocked if it tries to perform further GL commands
326842542f5fSchristos * after queueing a swap, though in the Intel case after queueing a flip, the
326942542f5fSchristos * client is free to queue more commands; they'll block in the kernel if
327042542f5fSchristos * they access buffers busy with the flip.
327142542f5fSchristos *
327242542f5fSchristos * When the swap is complete, the driver should call into the server so it
327342542f5fSchristos * can send any swap complete events that have been requested.
327442542f5fSchristos */
327542542f5fSchristosstatic int
327642542f5fSchristossna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
327742542f5fSchristos		       DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
327842542f5fSchristos		       CARD64 remainder, DRI2SwapEventPtr func, void *data)
327942542f5fSchristos{
328042542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
328142542f5fSchristos	xf86CrtcPtr crtc = NULL;
328242542f5fSchristos	struct sna_dri2_event *info = NULL;
328313496ba1Ssnj	int type = DRI2_EXCHANGE_COMPLETE;
328442542f5fSchristos	CARD64 current_msc;
328563ef14f0Smrg	bool immediate;
328642542f5fSchristos
328763ef14f0Smrg	DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d, active=%d) , front=%u (refs=%d/%d, flush=%d, active=%d)\n",
328842542f5fSchristos	     __FUNCTION__,
328942542f5fSchristos	     (long)draw->id, draw->width, draw->height,
329042542f5fSchristos	     get_drawable_pixmap(draw)->drawable.serialNumber,
329142542f5fSchristos	     get_drawable_pixmap(draw)->drawable.width,
329242542f5fSchristos	     get_drawable_pixmap(draw)->drawable.height,
329342542f5fSchristos	     get_private(back)->bo->handle,
329442542f5fSchristos	     get_private(back)->refcnt,
329542542f5fSchristos	     get_private(back)->bo->refcnt,
329642542f5fSchristos	     get_private(back)->bo->flush,
329763ef14f0Smrg	     get_private(back)->bo->active_scanout,
329842542f5fSchristos	     get_private(front)->bo->handle,
329942542f5fSchristos	     get_private(front)->refcnt,
330042542f5fSchristos	     get_private(front)->bo->refcnt,
330163ef14f0Smrg	     get_private(front)->bo->flush,
330263ef14f0Smrg	     get_private(front)->bo->active_scanout));
330342542f5fSchristos
330442542f5fSchristos	DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n",
330542542f5fSchristos	     __FUNCTION__,
330642542f5fSchristos	     (long long)*target_msc,
330742542f5fSchristos	     (long long)divisor,
330842542f5fSchristos	     (long long)remainder));
330942542f5fSchristos
331063ef14f0Smrg	assert(front != back);
331163ef14f0Smrg	assert(get_private(front) != get_private(back));
331263ef14f0Smrg
331342542f5fSchristos	assert(get_private(front)->refcnt);
331442542f5fSchristos	assert(get_private(back)->refcnt);
331542542f5fSchristos
331663ef14f0Smrg	assert(get_private(back)->bo != get_private(front)->bo);
331742542f5fSchristos	assert(get_private(front)->bo->refcnt);
331842542f5fSchristos	assert(get_private(back)->bo->refcnt);
331942542f5fSchristos
332063ef14f0Smrg	assert(get_private(front)->bo->active_scanout);
332163ef14f0Smrg	assert(!get_private(back)->bo->active_scanout);
332263ef14f0Smrg
332313496ba1Ssnj	if (get_private(front)->pixmap != get_drawable_pixmap(draw)) {
332413496ba1Ssnj		DBG(("%s: decoupled DRI2 front pixmap=%ld, actual pixmap=%ld\n",
332513496ba1Ssnj		     __FUNCTION__,
332613496ba1Ssnj		     get_private(front)->pixmap->drawable.serialNumber,
332713496ba1Ssnj		     get_drawable_pixmap(draw)->drawable.serialNumber));
332842542f5fSchristos		goto skip;
332913496ba1Ssnj	}
333042542f5fSchristos
333113496ba1Ssnj	if (get_private(back)->stale) {
333213496ba1Ssnj		DBG(("%s: stale back buffer\n", __FUNCTION__));
333342542f5fSchristos		goto skip;
333413496ba1Ssnj	}
333542542f5fSchristos
333642542f5fSchristos	if (draw->type != DRAWABLE_PIXMAP) {
333742542f5fSchristos		WindowPtr win = (WindowPtr)draw;
333842542f5fSchristos		struct dri2_window *priv = dri2_window(win);
333963ef14f0Smrg
334042542f5fSchristos		if (priv->front) {
334163ef14f0Smrg			front = priv->front;
334263ef14f0Smrg			assert(front->attachment == DRI2BufferFrontLeft);
334363ef14f0Smrg			assert(get_private(front)->refcnt);
334463ef14f0Smrg			assert(get_private(front)->pixmap == get_drawable_pixmap(draw));
334542542f5fSchristos		}
334663ef14f0Smrg
334742542f5fSchristos		if (win->clipList.extents.x2 <= win->clipList.extents.x1 ||
334813496ba1Ssnj		    win->clipList.extents.y2 <= win->clipList.extents.y1) {
334913496ba1Ssnj			DBG(("%s: window clipped (%d, %d), (%d, %d)\n",
335013496ba1Ssnj			     __FUNCTION__,
335113496ba1Ssnj			     win->clipList.extents.x1,
335213496ba1Ssnj			     win->clipList.extents.y1,
335313496ba1Ssnj			     win->clipList.extents.x2,
335413496ba1Ssnj			     win->clipList.extents.y2));
335542542f5fSchristos			goto skip;
335613496ba1Ssnj		}
335742542f5fSchristos	}
335842542f5fSchristos
335963ef14f0Smrg	DBG(("%s: using front handle=%d, active_scanout?=%d, flush?=%d\n", __FUNCTION__, get_private(front)->bo->handle, get_private(front)->bo->active_scanout, sna_pixmap_from_drawable(draw)->flush));
336063ef14f0Smrg	assert(get_private(front)->bo->active_scanout);
336163ef14f0Smrg	assert(sna_pixmap_from_drawable(draw)->flush);
336263ef14f0Smrg
336342542f5fSchristos	/* Drawable not displayed... just complete the swap */
336442542f5fSchristos	if ((sna->flags & SNA_NO_WAIT) == 0)
336542542f5fSchristos		crtc = sna_dri2_get_crtc(draw);
336642542f5fSchristos	if (crtc == NULL) {
336742542f5fSchristos		DBG(("%s: off-screen, immediate update\n", __FUNCTION__));
336842542f5fSchristos		goto blit;
336942542f5fSchristos	}
337042542f5fSchristos
337142542f5fSchristos	assert(draw->type != DRAWABLE_PIXMAP);
337242542f5fSchristos
337342542f5fSchristos	while (dri2_chain(draw) && has_pending_events(sna)) {
337442542f5fSchristos		DBG(("%s: flushing pending events\n", __FUNCTION__));
337542542f5fSchristos		sna_mode_wakeup(sna);
337642542f5fSchristos	}
337742542f5fSchristos
337863ef14f0Smrg	immediate = immediate_swap(sna, draw, crtc,
337942542f5fSchristos				   target_msc, divisor, remainder,
338063ef14f0Smrg				   &current_msc);
338142542f5fSchristos
338242542f5fSchristos	if (can_flip(sna, draw, front, back, crtc) &&
338342542f5fSchristos	    sna_dri2_schedule_flip(client, draw, crtc, front, back,
338463ef14f0Smrg				  immediate, target_msc, current_msc,
338542542f5fSchristos				  func, data))
338642542f5fSchristos		return TRUE;
338742542f5fSchristos
338863ef14f0Smrg	info = sna_dri2_add_event(sna, draw, client, crtc);
338942542f5fSchristos	if (!info)
339042542f5fSchristos		goto blit;
339142542f5fSchristos
339242542f5fSchristos	assert(info->crtc == crtc);
339342542f5fSchristos	info->event_complete = func;
339442542f5fSchristos	info->event_data = data;
339563ef14f0Smrg	assert(info->draw);
339663ef14f0Smrg	info->signal = true;
339742542f5fSchristos
339863ef14f0Smrg	assert(front != back);
339942542f5fSchristos	info->front = sna_dri2_reference_buffer(front);
340042542f5fSchristos	info->back = sna_dri2_reference_buffer(back);
340142542f5fSchristos
340263ef14f0Smrg	if (immediate) {
340342542f5fSchristos		bool sync = current_msc < *target_msc;
340463ef14f0Smrg		sna_dri2_immediate_blit(sna, info, sync);
340542542f5fSchristos		*target_msc = current_msc + sync;
340663ef14f0Smrg		DBG(("%s: reported target_msc=%llu\n",
340763ef14f0Smrg		     __FUNCTION__, *target_msc));
340842542f5fSchristos		return TRUE;
340942542f5fSchristos	}
341042542f5fSchristos
341142542f5fSchristos	info->type = SWAP;
341242542f5fSchristos	if (*target_msc <= current_msc + 1) {
341342542f5fSchristos		DBG(("%s: performing blit before queueing\n", __FUNCTION__));
341463ef14f0Smrg		__sna_dri2_copy_event(info, DRI2_SYNC);
341563ef14f0Smrg		info->type = SWAP_COMPLETE;
341663ef14f0Smrg		if (!sna_next_vblank(info))
341763ef14f0Smrg			goto fake;
341863ef14f0Smrg
341963ef14f0Smrg		DBG(("%s: reported target_msc=%llu\n",
342063ef14f0Smrg		     __FUNCTION__, *target_msc));
342142542f5fSchristos		*target_msc = current_msc + 1;
342263ef14f0Smrg		swap_limit(draw, 2);
342363ef14f0Smrg	} else {
342463ef14f0Smrg		if (!sna_wait_vblank(info,
342563ef14f0Smrg				     draw_target_seq(draw, *target_msc - 1)))
342663ef14f0Smrg			goto blit;
342742542f5fSchristos
342863ef14f0Smrg		DBG(("%s: reported target_msc=%llu (in)\n",
342963ef14f0Smrg		     __FUNCTION__, *target_msc));
343063ef14f0Smrg		swap_limit(draw, 1);
343163ef14f0Smrg	}
343242542f5fSchristos
343342542f5fSchristos	return TRUE;
343442542f5fSchristos
343542542f5fSchristosblit:
343642542f5fSchristos	DBG(("%s -- blit\n", __FUNCTION__));
343713496ba1Ssnj	if (can_xchg(sna, draw, front, back)) {
343842542f5fSchristos		sna_dri2_xchg(draw, front, back);
343913496ba1Ssnj	} else {
344063ef14f0Smrg		__sna_dri2_copy_region(sna, draw, NULL, back, front, 0);
344163ef14f0Smrg		front->flags = back->flags;
344213496ba1Ssnj		type = DRI2_BLIT_COMPLETE;
344313496ba1Ssnj	}
344463ef14f0Smrg	if (draw->type == DRAWABLE_PIXMAP)
344563ef14f0Smrg		goto fake;
344642542f5fSchristosskip:
344742542f5fSchristos	DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
344863ef14f0Smrg	if (crtc == NULL && (sna->flags & SNA_NO_WAIT) == 0)
344963ef14f0Smrg		crtc = sna_primary_crtc(sna);
345063ef14f0Smrg	if (crtc && sna_crtc_is_on(crtc)) {
345163ef14f0Smrg		if (info == NULL)
345263ef14f0Smrg			info = sna_dri2_add_event(sna, draw, client, crtc);
345363ef14f0Smrg		if (info != dri2_chain(draw))
345463ef14f0Smrg			goto fake;
345563ef14f0Smrg
345663ef14f0Smrg		assert(info->crtc == crtc);
345763ef14f0Smrg
345863ef14f0Smrg		info->type = SWAP_COMPLETE;
345963ef14f0Smrg		info->event_complete = func;
346063ef14f0Smrg		info->event_data = data;
346163ef14f0Smrg		assert(info->draw);
346263ef14f0Smrg		info->signal = true;
346363ef14f0Smrg
346463ef14f0Smrg		if (info->front == NULL)
346563ef14f0Smrg			info->front = sna_dri2_reference_buffer(front);
346663ef14f0Smrg		if (info->back == NULL)
346763ef14f0Smrg			info->back = sna_dri2_reference_buffer(back);
346863ef14f0Smrg
346963ef14f0Smrg		if (!sna_next_vblank(info))
347063ef14f0Smrg			goto fake;
347163ef14f0Smrg
347263ef14f0Smrg		swap_limit(draw, 1);
347363ef14f0Smrg	} else {
347463ef14f0Smrgfake:
347563ef14f0Smrg		/* XXX Use a Timer to throttle the client? */
347663ef14f0Smrg		fake_swap_complete(sna, client, draw, crtc, type, func, data);
347763ef14f0Smrg		if (info) {
347863ef14f0Smrg			assert(info->draw);
347963ef14f0Smrg			info->signal = false;
348063ef14f0Smrg			sna_dri2_event_free(info);
348163ef14f0Smrg		}
348263ef14f0Smrg	}
348363ef14f0Smrg	DBG(("%s: reported target_msc=%llu (in)\n", __FUNCTION__, *target_msc));
348442542f5fSchristos	return TRUE;
348542542f5fSchristos}
348642542f5fSchristos
348742542f5fSchristos/*
348842542f5fSchristos * Get current frame count and frame count timestamp, based on drawable's
348942542f5fSchristos * crtc.
349042542f5fSchristos */
349142542f5fSchristosstatic int
349242542f5fSchristossna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
349342542f5fSchristos{
349442542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
349542542f5fSchristos	xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
349642542f5fSchristos	const struct ust_msc *swap;
349763ef14f0Smrg	union drm_wait_vblank vbl;
349842542f5fSchristos
349942542f5fSchristos	DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
350063ef14f0Smrg	     crtc ? sna_crtc_pipe(crtc) : -1));
350142542f5fSchristos
350263ef14f0Smrg	/* Drawable not displayed, make up a *monotonic* value */
350363ef14f0Smrg	if (crtc == NULL)
350463ef14f0Smrg		crtc = sna_primary_crtc(sna);
350563ef14f0Smrg	if (crtc == NULL)
350663ef14f0Smrg		return FALSE;
350742542f5fSchristos
350863ef14f0Smrg	if (sna_query_vblank(sna, crtc, &vbl) == 0)
350963ef14f0Smrg		sna_crtc_record_vblank(crtc, &vbl);
351042542f5fSchristos
351142542f5fSchristos	swap = sna_crtc_last_swap(crtc);
351242542f5fSchristos	*msc = draw_current_msc(draw, crtc, swap->msc);
351342542f5fSchristos	*ust = ust64(swap->tv_sec, swap->tv_usec);
351463ef14f0Smrg	DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__,
351563ef14f0Smrg	     (long long)*msc, swap->msc, (long long)*ust));
351642542f5fSchristos	return TRUE;
351742542f5fSchristos}
351842542f5fSchristos
351942542f5fSchristos/*
352042542f5fSchristos * Request a DRM event when the requested conditions will be satisfied.
352142542f5fSchristos *
352242542f5fSchristos * We need to handle the event and ask the server to wake up the client when
352342542f5fSchristos * we receive it.
352442542f5fSchristos */
352542542f5fSchristosstatic int
352642542f5fSchristossna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
352742542f5fSchristos			   CARD64 divisor, CARD64 remainder)
352842542f5fSchristos{
352942542f5fSchristos	struct sna *sna = to_sna_from_drawable(draw);
353042542f5fSchristos	struct sna_dri2_event *info = NULL;
353142542f5fSchristos	xf86CrtcPtr crtc;
353242542f5fSchristos	CARD64 current_msc;
353342542f5fSchristos	const struct ust_msc *swap;
353442542f5fSchristos
353542542f5fSchristos	crtc = sna_dri2_get_crtc(draw);
353642542f5fSchristos	DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
353763ef14f0Smrg	     __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1,
353842542f5fSchristos	     (long long)target_msc,
353942542f5fSchristos	     (long long)divisor,
354042542f5fSchristos	     (long long)remainder));
354142542f5fSchristos
354242542f5fSchristos	/* Drawable not visible, return immediately */
354342542f5fSchristos	if (crtc == NULL)
354463ef14f0Smrg		crtc = sna_primary_crtc(sna);
354563ef14f0Smrg	if (crtc == NULL)
354663ef14f0Smrg		return FALSE;
354742542f5fSchristos
354863ef14f0Smrg	current_msc = get_current_msc(sna, draw, crtc);
354942542f5fSchristos
355042542f5fSchristos	/* If target_msc already reached or passed, set it to
355142542f5fSchristos	 * current_msc to ensure we return a reasonable value back
355242542f5fSchristos	 * to the caller. This keeps the client from continually
355342542f5fSchristos	 * sending us MSC targets from the past by forcibly updating
355442542f5fSchristos	 * their count on this call.
355542542f5fSchristos	 */
355642542f5fSchristos	if (divisor == 0 && current_msc >= target_msc)
355742542f5fSchristos		goto out_complete;
355842542f5fSchristos
355963ef14f0Smrg	info = sna_dri2_add_event(sna, draw, client, crtc);
356042542f5fSchristos	if (!info)
356142542f5fSchristos		goto out_complete;
356242542f5fSchristos
356342542f5fSchristos	assert(info->crtc == crtc);
356442542f5fSchristos	info->type = WAITMSC;
356542542f5fSchristos
356642542f5fSchristos	/*
356742542f5fSchristos	 * If divisor is zero, or current_msc is smaller than target_msc,
356842542f5fSchristos	 * we just need to make sure target_msc passes before waking up the
356942542f5fSchristos	 * client. Otherwise, compute the next msc to match divisor/remainder.
357042542f5fSchristos	 */
357142542f5fSchristos	if (divisor && current_msc >= target_msc) {
357242542f5fSchristos		DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
357342542f5fSchristos		     __FUNCTION__,
357442542f5fSchristos		     (long long)current_msc,
357542542f5fSchristos		     (long long)target_msc,
357642542f5fSchristos		     (long long)divisor,
357742542f5fSchristos		     (long long)remainder));
357842542f5fSchristos		target_msc = current_msc + remainder - current_msc % divisor;
357942542f5fSchristos		if (target_msc <= current_msc)
358042542f5fSchristos			target_msc += divisor;
358142542f5fSchristos	}
358242542f5fSchristos
358363ef14f0Smrg	if (!sna_wait_vblank(info, draw_target_seq(draw, target_msc)))
358442542f5fSchristos		goto out_free_info;
358542542f5fSchristos
358642542f5fSchristos	DRI2BlockClient(client, draw);
358742542f5fSchristos	return TRUE;
358842542f5fSchristos
358942542f5fSchristosout_free_info:
359013496ba1Ssnj	sna_dri2_event_free(info);
359142542f5fSchristosout_complete:
359242542f5fSchristos	swap = sna_crtc_last_swap(crtc);
359342542f5fSchristos	DRI2WaitMSCComplete(client, draw,
359442542f5fSchristos			    draw_current_msc(draw, crtc, swap->msc),
359542542f5fSchristos			    swap->tv_sec, swap->tv_usec);
359642542f5fSchristos	return TRUE;
359742542f5fSchristos}
359842542f5fSchristos#else
359942542f5fSchristosvoid sna_dri2_destroy_window(WindowPtr win) { }
360013496ba1Ssnjvoid sna_dri2_decouple_window(WindowPtr win) { }
360142542f5fSchristos#endif
360242542f5fSchristos
360342542f5fSchristosstatic bool has_i830_dri(void)
360442542f5fSchristos{
360542542f5fSchristos	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
360642542f5fSchristos}
360742542f5fSchristos
360842542f5fSchristosstatic int
360942542f5fSchristosnamecmp(const char *s1, const char *s2)
361042542f5fSchristos{
361142542f5fSchristos	char c1, c2;
361242542f5fSchristos
361342542f5fSchristos	if (!s1 || *s1 == 0) {
361442542f5fSchristos		if (!s2 || *s2 == 0)
361542542f5fSchristos			return 0;
361642542f5fSchristos		else
361742542f5fSchristos			return 1;
361842542f5fSchristos	}
361942542f5fSchristos
362042542f5fSchristos	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
362142542f5fSchristos		s1++;
362242542f5fSchristos
362342542f5fSchristos	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
362442542f5fSchristos		s2++;
362542542f5fSchristos
362642542f5fSchristos	c1 = isupper(*s1) ? tolower(*s1) : *s1;
362742542f5fSchristos	c2 = isupper(*s2) ? tolower(*s2) : *s2;
362842542f5fSchristos	while (c1 == c2) {
362942542f5fSchristos		if (c1 == '\0')
363042542f5fSchristos			return 0;
363142542f5fSchristos
363242542f5fSchristos		s1++;
363342542f5fSchristos		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
363442542f5fSchristos			s1++;
363542542f5fSchristos
363642542f5fSchristos		s2++;
363742542f5fSchristos		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
363842542f5fSchristos			s2++;
363942542f5fSchristos
364042542f5fSchristos		c1 = isupper(*s1) ? tolower(*s1) : *s1;
364142542f5fSchristos		c2 = isupper(*s2) ? tolower(*s2) : *s2;
364242542f5fSchristos	}
364342542f5fSchristos
364442542f5fSchristos	return c1 - c2;
364542542f5fSchristos}
364642542f5fSchristos
364742542f5fSchristosstatic bool is_level(const char **str)
364842542f5fSchristos{
364942542f5fSchristos	const char *s = *str;
365042542f5fSchristos	char *end;
365142542f5fSchristos	unsigned val;
365242542f5fSchristos
365342542f5fSchristos	if (s == NULL || *s == '\0')
365442542f5fSchristos		return true;
365542542f5fSchristos
365642542f5fSchristos	if (namecmp(s, "on") == 0)
365742542f5fSchristos		return true;
365842542f5fSchristos	if (namecmp(s, "true") == 0)
365942542f5fSchristos		return true;
366042542f5fSchristos	if (namecmp(s, "yes") == 0)
366142542f5fSchristos		return true;
366242542f5fSchristos
366342542f5fSchristos	if (namecmp(s, "0") == 0)
366442542f5fSchristos		return true;
366542542f5fSchristos	if (namecmp(s, "off") == 0)
366642542f5fSchristos		return true;
366742542f5fSchristos	if (namecmp(s, "false") == 0)
366842542f5fSchristos		return true;
366942542f5fSchristos	if (namecmp(s, "no") == 0)
367042542f5fSchristos		return true;
367142542f5fSchristos
367242542f5fSchristos	val = strtoul(s, &end, 0);
367342542f5fSchristos	if (val && *end == '\0')
367442542f5fSchristos		return true;
367542542f5fSchristos	if (val && *end == ':')
367642542f5fSchristos		*str = end + 1;
367742542f5fSchristos	return false;
367842542f5fSchristos}
367942542f5fSchristos
368063ef14f0Smrgstatic const char *options_get_dri(struct sna *sna)
368163ef14f0Smrg{
368263ef14f0Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
368363ef14f0Smrg	return xf86GetOptValString(sna->Options, OPTION_DRI);
368463ef14f0Smrg#else
368563ef14f0Smrg	return NULL;
368663ef14f0Smrg#endif
368763ef14f0Smrg}
368863ef14f0Smrg
368942542f5fSchristosstatic const char *dri_driver_name(struct sna *sna)
369042542f5fSchristos{
369163ef14f0Smrg	const char *s = options_get_dri(sna);
369242542f5fSchristos
369342542f5fSchristos	if (is_level(&s)) {
369442542f5fSchristos		if (sna->kgem.gen < 030)
369542542f5fSchristos			return has_i830_dri() ? "i830" : "i915";
369642542f5fSchristos		else if (sna->kgem.gen < 040)
369742542f5fSchristos			return "i915";
369842542f5fSchristos		else
369942542f5fSchristos			return "i965";
370042542f5fSchristos	}
370142542f5fSchristos
370242542f5fSchristos	return s;
370342542f5fSchristos}
370442542f5fSchristos
370542542f5fSchristosbool sna_dri2_open(struct sna *sna, ScreenPtr screen)
370642542f5fSchristos{
370742542f5fSchristos	DRI2InfoRec info;
370842542f5fSchristos	int major = 1, minor = 0;
370942542f5fSchristos#if DRI2INFOREC_VERSION >= 4
371042542f5fSchristos	const char *driverNames[2];
371142542f5fSchristos#endif
371242542f5fSchristos
371342542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
371442542f5fSchristos
371542542f5fSchristos	if (wedged(sna)) {
371642542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
371763ef14f0Smrg			   "loading DRI2 whilst acceleration is disabled.\n");
371842542f5fSchristos	}
371942542f5fSchristos
372042542f5fSchristos	if (xf86LoaderCheckSymbol("DRI2Version"))
372142542f5fSchristos		DRI2Version(&major, &minor);
372242542f5fSchristos
372342542f5fSchristos	if (minor < 1) {
372442542f5fSchristos		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
372542542f5fSchristos			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
372642542f5fSchristos		return false;
372742542f5fSchristos	}
372842542f5fSchristos
372942542f5fSchristos	memset(&info, '\0', sizeof(info));
373042542f5fSchristos	info.fd = sna->kgem.fd;
373142542f5fSchristos	info.driverName = dri_driver_name(sna);
373263ef14f0Smrg	info.deviceName = intel_get_master_name(sna->dev);
373342542f5fSchristos
373442542f5fSchristos	DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
373542542f5fSchristos	     __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
373642542f5fSchristos
373742542f5fSchristos#if DRI2INFOREC_VERSION == 2
373842542f5fSchristos	/* The ABI between 2 and 3 was broken so we could get rid of
373942542f5fSchristos	 * the multi-buffer alloc functions.  Make sure we indicate the
374042542f5fSchristos	 * right version so DRI2 can reject us if it's version 3 or above. */
374142542f5fSchristos	info.version = 2;
374242542f5fSchristos#else
374342542f5fSchristos	info.version = 3;
374442542f5fSchristos#endif
374542542f5fSchristos	info.CreateBuffer = sna_dri2_create_buffer;
374642542f5fSchristos	info.DestroyBuffer = sna_dri2_destroy_buffer;
374742542f5fSchristos
374842542f5fSchristos	info.CopyRegion = sna_dri2_copy_region;
374942542f5fSchristos#if DRI2INFOREC_VERSION >= 4
375042542f5fSchristos	info.version = 4;
375142542f5fSchristos	info.ScheduleSwap = sna_dri2_schedule_swap;
375242542f5fSchristos	info.GetMSC = sna_dri2_get_msc;
375342542f5fSchristos	info.ScheduleWaitMSC = sna_dri2_schedule_wait_msc;
375442542f5fSchristos	info.numDrivers = 2;
375542542f5fSchristos	info.driverNames = driverNames;
375642542f5fSchristos	driverNames[0] = info.driverName;
375763ef14f0Smrg	driverNames[1] = "va_gl";
375842542f5fSchristos#endif
375942542f5fSchristos
376042542f5fSchristos#if DRI2INFOREC_VERSION >= 6
376113496ba1Ssnj	if (xorg_can_triple_buffer()) {
376263ef14f0Smrg		DBG(("%s: enabling Xorg triple buffering\n", __FUNCTION__));
376342542f5fSchristos		info.version = 6;
376442542f5fSchristos		info.SwapLimitValidate = sna_dri2_swap_limit_validate;
376542542f5fSchristos		info.ReuseBufferNotify = sna_dri2_reuse_buffer;
376642542f5fSchristos	}
376742542f5fSchristos#endif
376842542f5fSchristos
376942542f5fSchristos#if USE_ASYNC_SWAP
377063ef14f0Smrg	DBG(("%s: enabled async swap and buffer age\n", __FUNCTION__));
377142542f5fSchristos	info.version = 10;
377242542f5fSchristos	info.scheduleSwap0 = 1;
377363ef14f0Smrg	info.bufferAge = 1;
377442542f5fSchristos#endif
377542542f5fSchristos
377642542f5fSchristos	return DRI2ScreenInit(screen, &info);
377742542f5fSchristos}
377842542f5fSchristos
377942542f5fSchristosvoid sna_dri2_close(struct sna *sna, ScreenPtr screen)
378042542f5fSchristos{
378142542f5fSchristos	DBG(("%s()\n", __FUNCTION__));
378242542f5fSchristos	DRI2CloseScreen(screen);
378342542f5fSchristos}
3784