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