1428d7b3dSmrg/**************************************************************************
2428d7b3dSmrg
3428d7b3dSmrgCopyright 2001 VA Linux Systems Inc., Fremont, California.
4428d7b3dSmrgCopyright © 2002 by David Dawes
5428d7b3dSmrg
6428d7b3dSmrgAll Rights Reserved.
7428d7b3dSmrg
8428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a
9428d7b3dSmrgcopy of this software and associated documentation files (the "Software"),
10428d7b3dSmrgto deal in the Software without restriction, including without limitation
11428d7b3dSmrgon the rights to use, copy, modify, merge, publish, distribute, sub
12428d7b3dSmrglicense, and/or sell copies of the Software, and to permit persons to whom
13428d7b3dSmrgthe Software is furnished to do so, subject to the following conditions:
14428d7b3dSmrg
15428d7b3dSmrgThe above copyright notice and this permission notice (including the next
16428d7b3dSmrgparagraph) shall be included in all copies or substantial portions of the
17428d7b3dSmrgSoftware.
18428d7b3dSmrg
19428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20428d7b3dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21428d7b3dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22428d7b3dSmrgATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23428d7b3dSmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24428d7b3dSmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25428d7b3dSmrgUSE OR OTHER DEALINGS IN THE SOFTWARE.
26428d7b3dSmrg
27428d7b3dSmrg**************************************************************************/
28428d7b3dSmrg
29428d7b3dSmrg/*
30428d7b3dSmrg * Authors: Jeff Hartmann <jhartmann@valinux.com>
31428d7b3dSmrg *          David Dawes <dawes@xfree86.org>
32428d7b3dSmrg *          Keith Whitwell <keith@tungstengraphics.com>
33428d7b3dSmrg */
34428d7b3dSmrg
35428d7b3dSmrg#ifdef HAVE_CONFIG_H
36428d7b3dSmrg#include "config.h"
37428d7b3dSmrg#endif
38428d7b3dSmrg
39428d7b3dSmrg#include <stdio.h>
40428d7b3dSmrg#include <string.h>
41428d7b3dSmrg#include <assert.h>
42428d7b3dSmrg#include <sys/types.h>
43428d7b3dSmrg#include <sys/stat.h>
44428d7b3dSmrg#include <sys/ioctl.h>
45428d7b3dSmrg#include <unistd.h>
46428d7b3dSmrg#include <fcntl.h>
47428d7b3dSmrg#include <sys/time.h>
48428d7b3dSmrg#include <time.h>
49428d7b3dSmrg#include <errno.h>
50428d7b3dSmrg
51428d7b3dSmrg#include "xorg-server.h"
52428d7b3dSmrg#include "xf86.h"
53428d7b3dSmrg#include "xf86_OSproc.h"
54428d7b3dSmrg
55428d7b3dSmrg#include "xf86Pci.h"
56428d7b3dSmrg#include "xf86drm.h"
57428d7b3dSmrg
58428d7b3dSmrg#include "windowstr.h"
59428d7b3dSmrg#include "shadow.h"
60428d7b3dSmrg#include "fb.h"
61428d7b3dSmrg
62428d7b3dSmrg#include "intel.h"
63428d7b3dSmrg#include "i830_reg.h"
64428d7b3dSmrg
65428d7b3dSmrg#include "i915_drm.h"
66428d7b3dSmrg
67428d7b3dSmrg#include "dri2.h"
68428d7b3dSmrg
69428d7b3dSmrg#if USE_UXA
70428d7b3dSmrg#include "intel_uxa.h"
71428d7b3dSmrg#endif
72428d7b3dSmrg
73428d7b3dSmrgtypedef struct {
74428d7b3dSmrg	int refcnt;
75428d7b3dSmrg	PixmapPtr pixmap;
76428d7b3dSmrg} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
77428d7b3dSmrg
78428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC
79428d7b3dSmrgstatic DevPrivateKeyRec i830_client_key;
80428d7b3dSmrg#else
81428d7b3dSmrgstatic int i830_client_key;
82428d7b3dSmrg#endif
83428d7b3dSmrg
84428d7b3dSmrgstatic uint32_t pixmap_flink(PixmapPtr pixmap)
85428d7b3dSmrg{
86428d7b3dSmrg	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
87428d7b3dSmrg	uint32_t name;
88428d7b3dSmrg
89428d7b3dSmrg	if (priv == NULL || priv->bo == NULL)
90428d7b3dSmrg		return 0;
91428d7b3dSmrg
92428d7b3dSmrg	if (dri_bo_flink(priv->bo, &name) != 0)
93428d7b3dSmrg		return 0;
94428d7b3dSmrg
95428d7b3dSmrg	priv->pinned |= PIN_DRI2;
96428d7b3dSmrg	return name;
97428d7b3dSmrg}
98428d7b3dSmrg
99428d7b3dSmrgstatic PixmapPtr get_front_buffer(DrawablePtr drawable)
100428d7b3dSmrg{
101428d7b3dSmrg	PixmapPtr pixmap;
102428d7b3dSmrg
103428d7b3dSmrg	pixmap = get_drawable_pixmap(drawable);
104428d7b3dSmrg	if (!intel_get_pixmap_bo(pixmap))
105428d7b3dSmrg		return NULL;
106428d7b3dSmrg
107428d7b3dSmrg	pixmap->refcnt++;
108428d7b3dSmrg	return pixmap;
109428d7b3dSmrg}
110428d7b3dSmrg
111428d7b3dSmrg#if DRI2INFOREC_VERSION < 2
112428d7b3dSmrgstatic DRI2BufferPtr
113428d7b3dSmrgI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
114428d7b3dSmrg		      int count)
115428d7b3dSmrg{
116428d7b3dSmrg	ScreenPtr screen = drawable->pScreen;
117428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
118428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
119428d7b3dSmrg	DRI2BufferPtr buffers;
120428d7b3dSmrg	I830DRI2BufferPrivatePtr privates;
121428d7b3dSmrg	PixmapPtr pixmap, pDepthPixmap;
122428d7b3dSmrg	int i;
123428d7b3dSmrg
124428d7b3dSmrg	buffers = calloc(count, sizeof *buffers);
125428d7b3dSmrg	if (buffers == NULL)
126428d7b3dSmrg		return NULL;
127428d7b3dSmrg	privates = calloc(count, sizeof *privates);
128428d7b3dSmrg	if (privates == NULL) {
129428d7b3dSmrg		free(buffers);
130428d7b3dSmrg		return NULL;
131428d7b3dSmrg	}
132428d7b3dSmrg
133428d7b3dSmrg	pDepthPixmap = NULL;
134428d7b3dSmrg	for (i = 0; i < count; i++) {
135428d7b3dSmrg		pixmap = NULL;
136428d7b3dSmrg		if (attachments[i] == DRI2BufferFrontLeft) {
137428d7b3dSmrg			pixmap = get_front_buffer(drawable);
138428d7b3dSmrg
139428d7b3dSmrg			if (pixmap == NULL)
140428d7b3dSmrg				drawable = &(get_drawable_pixmap(drawable)->drawable);
141428d7b3dSmrg		} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
142428d7b3dSmrg			pixmap = pDepthPixmap;
143428d7b3dSmrg			pixmap->refcnt++;
144428d7b3dSmrg		}
145428d7b3dSmrg
146428d7b3dSmrg		if (pixmap == NULL) {
147428d7b3dSmrg			unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
148428d7b3dSmrg
149428d7b3dSmrg			if (intel->tiling & INTEL_TILING_3D) {
150428d7b3dSmrg				switch (attachments[i]) {
151428d7b3dSmrg				case DRI2BufferDepth:
152428d7b3dSmrg					if (SUPPORTS_YTILING(intel))
153428d7b3dSmrg						hint |= INTEL_CREATE_PIXMAP_TILING_Y;
154428d7b3dSmrg					else
155428d7b3dSmrg						hint |= INTEL_CREATE_PIXMAP_TILING_X;
156428d7b3dSmrg					break;
157428d7b3dSmrg				case DRI2BufferFakeFrontLeft:
158428d7b3dSmrg				case DRI2BufferFakeFrontRight:
159428d7b3dSmrg				case DRI2BufferBackLeft:
160428d7b3dSmrg				case DRI2BufferBackRight:
161428d7b3dSmrg					hint |= INTEL_CREATE_PIXMAP_TILING_X;
162428d7b3dSmrg					break;
163428d7b3dSmrg				}
164428d7b3dSmrg			}
165428d7b3dSmrg
166428d7b3dSmrg			pixmap = screen->CreatePixmap(screen,
167428d7b3dSmrg						      drawable->width,
168428d7b3dSmrg						      drawable->height,
169428d7b3dSmrg						      drawable->depth,
170428d7b3dSmrg						      hint);
171428d7b3dSmrg			if (pixmap == NULL ||
172428d7b3dSmrg			    intel_get_pixmap_bo(pixmap) == NULL)
173428d7b3dSmrg			{
174428d7b3dSmrg				if (pixmap)
175428d7b3dSmrg					screen->DestroyPixmap(pixmap);
176428d7b3dSmrg				goto unwind;
177428d7b3dSmrg			}
178428d7b3dSmrg		}
179428d7b3dSmrg
180428d7b3dSmrg		if (attachments[i] == DRI2BufferDepth)
181428d7b3dSmrg			pDepthPixmap = pixmap;
182428d7b3dSmrg
183428d7b3dSmrg		buffers[i].attachment = attachments[i];
184428d7b3dSmrg		buffers[i].pitch = pixmap->devKind;
185428d7b3dSmrg		buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
186428d7b3dSmrg		buffers[i].driverPrivate = &privates[i];
187428d7b3dSmrg		buffers[i].flags = 0;	/* not tiled */
188428d7b3dSmrg		privates[i].refcnt = 1;
189428d7b3dSmrg		privates[i].pixmap = pixmap;
190428d7b3dSmrg
191428d7b3dSmrg		if ((buffers[i].name = pixmap_flink(pixmap)) == 0) {
192428d7b3dSmrg			/* failed to name buffer */
193428d7b3dSmrg			screen->DestroyPixmap(pixmap);
194428d7b3dSmrg			goto unwind;
195428d7b3dSmrg		}
196428d7b3dSmrg	}
197428d7b3dSmrg
198428d7b3dSmrg	return buffers;
199428d7b3dSmrg
200428d7b3dSmrgunwind:
201428d7b3dSmrg	while (i--)
202428d7b3dSmrg		screen->DestroyPixmap(privates[i].pixmap);
203428d7b3dSmrg	free(privates);
204428d7b3dSmrg	free(buffers);
205428d7b3dSmrg	return NULL;
206428d7b3dSmrg}
207428d7b3dSmrg
208428d7b3dSmrgstatic void
209428d7b3dSmrgI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
210428d7b3dSmrg{
211428d7b3dSmrg	ScreenPtr screen = drawable->pScreen;
212428d7b3dSmrg	I830DRI2BufferPrivatePtr private;
213428d7b3dSmrg	int i;
214428d7b3dSmrg
215428d7b3dSmrg	for (i = 0; i < count; i++) {
216428d7b3dSmrg		private = buffers[i].driverPrivate;
217428d7b3dSmrg		screen->DestroyPixmap(private->pixmap);
218428d7b3dSmrg	}
219428d7b3dSmrg
220428d7b3dSmrg	if (buffers) {
221428d7b3dSmrg		free(buffers[0].driverPrivate);
222428d7b3dSmrg		free(buffers);
223428d7b3dSmrg	}
224428d7b3dSmrg}
225428d7b3dSmrg
226428d7b3dSmrg#else
227428d7b3dSmrg
228428d7b3dSmrgstatic DRI2Buffer2Ptr
229428d7b3dSmrgI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
230428d7b3dSmrg		     unsigned int format)
231428d7b3dSmrg{
232428d7b3dSmrg	ScreenPtr screen = drawable->pScreen;
233428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
234428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
235428d7b3dSmrg	DRI2Buffer2Ptr buffer;
236428d7b3dSmrg	I830DRI2BufferPrivatePtr privates;
237428d7b3dSmrg	PixmapPtr pixmap;
238428d7b3dSmrg
239428d7b3dSmrg	buffer = calloc(1, sizeof *buffer);
240428d7b3dSmrg	if (buffer == NULL)
241428d7b3dSmrg		return NULL;
242428d7b3dSmrg	privates = calloc(1, sizeof *privates);
243428d7b3dSmrg	if (privates == NULL) {
244428d7b3dSmrg		free(buffer);
245428d7b3dSmrg		return NULL;
246428d7b3dSmrg	}
247428d7b3dSmrg
248428d7b3dSmrg	pixmap = NULL;
249428d7b3dSmrg	if (attachment == DRI2BufferFrontLeft) {
250428d7b3dSmrg		pixmap = get_front_buffer(drawable);
251428d7b3dSmrg		if (pixmap == NULL)
252428d7b3dSmrg			drawable = &(get_drawable_pixmap(drawable)->drawable);
253428d7b3dSmrg	}
254428d7b3dSmrg
255428d7b3dSmrg	if (pixmap == NULL) {
256428d7b3dSmrg		unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
257428d7b3dSmrg		int pixmap_width = drawable->width;
258428d7b3dSmrg		int pixmap_height = drawable->height;
259428d7b3dSmrg		int pixmap_cpp = (format != 0) ? format : drawable->depth;
260428d7b3dSmrg
261428d7b3dSmrg		if (intel->tiling & INTEL_TILING_3D) {
262428d7b3dSmrg			switch (attachment) {
263428d7b3dSmrg			case DRI2BufferDepth:
264428d7b3dSmrg			case DRI2BufferDepthStencil:
265428d7b3dSmrg			case DRI2BufferHiz:
266428d7b3dSmrg				if (SUPPORTS_YTILING(intel)) {
267428d7b3dSmrg					hint |= INTEL_CREATE_PIXMAP_TILING_Y;
268428d7b3dSmrg					break;
269428d7b3dSmrg				}
270428d7b3dSmrg			case DRI2BufferAccum:
271428d7b3dSmrg			case DRI2BufferBackLeft:
272428d7b3dSmrg			case DRI2BufferBackRight:
273428d7b3dSmrg			case DRI2BufferFakeFrontLeft:
274428d7b3dSmrg			case DRI2BufferFakeFrontRight:
275428d7b3dSmrg			case DRI2BufferFrontLeft:
276428d7b3dSmrg			case DRI2BufferFrontRight:
277428d7b3dSmrg				hint |= INTEL_CREATE_PIXMAP_TILING_X;
278428d7b3dSmrg				break;
279428d7b3dSmrg			case DRI2BufferStencil:
280428d7b3dSmrg				/*
281428d7b3dSmrg				 * The stencil buffer is W tiled. However, we
282428d7b3dSmrg				 * request from the kernel a non-tiled buffer
283428d7b3dSmrg				 * because the GTT is incapable of W fencing.
284428d7b3dSmrg				 */
285428d7b3dSmrg				hint |= INTEL_CREATE_PIXMAP_TILING_NONE;
286428d7b3dSmrg				break;
287428d7b3dSmrg			default:
288428d7b3dSmrg				free(privates);
289428d7b3dSmrg				free(buffer);
290428d7b3dSmrg				return NULL;
291428d7b3dSmrg                        }
292428d7b3dSmrg		}
293428d7b3dSmrg
294428d7b3dSmrg		/*
295428d7b3dSmrg		 * The stencil buffer has quirky pitch requirements.  From Vol
296428d7b3dSmrg		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
297428d7b3dSmrg		 * Pitch":
298428d7b3dSmrg		 *    The pitch must be set to 2x the value computed based on
299428d7b3dSmrg		 *    width, as the stencil buffer is stored with two rows
300428d7b3dSmrg		 *    interleaved.
301428d7b3dSmrg		 * To accomplish this, we resort to the nasty hack of doubling
302428d7b3dSmrg		 * the drm region's cpp and halving its height.
303428d7b3dSmrg		 *
304428d7b3dSmrg		 * If we neglect to double the pitch, then render corruption
305428d7b3dSmrg		 * occurs.
306428d7b3dSmrg		 */
307428d7b3dSmrg		if (attachment == DRI2BufferStencil) {
308428d7b3dSmrg			pixmap_width = ALIGN(pixmap_width, 64);
309428d7b3dSmrg			pixmap_height = ALIGN((pixmap_height + 1) / 2, 64);
310428d7b3dSmrg			pixmap_cpp *= 2;
311428d7b3dSmrg		}
312428d7b3dSmrg
313428d7b3dSmrg		pixmap = screen->CreatePixmap(screen,
314428d7b3dSmrg					      pixmap_width,
315428d7b3dSmrg					      pixmap_height,
316428d7b3dSmrg					      pixmap_cpp,
317428d7b3dSmrg					      hint);
318428d7b3dSmrg		if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) {
319428d7b3dSmrg			if (pixmap)
320428d7b3dSmrg				screen->DestroyPixmap(pixmap);
321428d7b3dSmrg			free(privates);
322428d7b3dSmrg			free(buffer);
323428d7b3dSmrg			return NULL;
324428d7b3dSmrg		}
325428d7b3dSmrg	}
326428d7b3dSmrg
327428d7b3dSmrg	buffer->attachment = attachment;
328428d7b3dSmrg	buffer->pitch = pixmap->devKind;
329428d7b3dSmrg	buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
330428d7b3dSmrg	buffer->driverPrivate = privates;
331428d7b3dSmrg	buffer->format = format;
332428d7b3dSmrg	buffer->flags = 0;	/* not tiled */
333428d7b3dSmrg	privates->refcnt = 1;
334428d7b3dSmrg	privates->pixmap = pixmap;
335428d7b3dSmrg
336428d7b3dSmrg	if ((buffer->name = pixmap_flink(pixmap)) == 0) {
337428d7b3dSmrg		/* failed to name buffer */
338428d7b3dSmrg		screen->DestroyPixmap(pixmap);
339428d7b3dSmrg		free(privates);
340428d7b3dSmrg		free(buffer);
341428d7b3dSmrg		return NULL;
342428d7b3dSmrg	}
343428d7b3dSmrg
344428d7b3dSmrg	return buffer;
345428d7b3dSmrg}
346428d7b3dSmrg
347428d7b3dSmrgstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
348428d7b3dSmrg{
349428d7b3dSmrg	if (buffer && buffer->driverPrivate) {
350428d7b3dSmrg		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
351428d7b3dSmrg		if (--private->refcnt == 0) {
352428d7b3dSmrg			ScreenPtr screen = private->pixmap->drawable.pScreen;
353428d7b3dSmrg			screen->DestroyPixmap(private->pixmap);
354428d7b3dSmrg
355428d7b3dSmrg			free(private);
356428d7b3dSmrg			free(buffer);
357428d7b3dSmrg		}
358428d7b3dSmrg	} else
359428d7b3dSmrg		free(buffer);
360428d7b3dSmrg}
361428d7b3dSmrg
362428d7b3dSmrg#endif
363428d7b3dSmrg
364428d7b3dSmrgstatic void
365428d7b3dSmrgI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
366428d7b3dSmrg		   DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
367428d7b3dSmrg{
368428d7b3dSmrg	I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate;
369428d7b3dSmrg	I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate;
370428d7b3dSmrg	ScreenPtr screen = drawable->pScreen;
371428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
372428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
373428d7b3dSmrg	DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
374428d7b3dSmrg		? drawable : &srcPrivate->pixmap->drawable;
375428d7b3dSmrg	DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
376428d7b3dSmrg		? drawable : &dstPrivate->pixmap->drawable;
377428d7b3dSmrg	RegionPtr pCopyClip;
378428d7b3dSmrg	GCPtr gc;
379428d7b3dSmrg
380428d7b3dSmrg	gc = GetScratchGC(dst->depth, screen);
381428d7b3dSmrg	if (!gc)
382428d7b3dSmrg		return;
383428d7b3dSmrg
384428d7b3dSmrg	pCopyClip = REGION_CREATE(screen, NULL, 0);
385428d7b3dSmrg	REGION_COPY(screen, pCopyClip, pRegion);
386428d7b3dSmrg	(*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
387428d7b3dSmrg	ValidateGC(dst, gc);
388428d7b3dSmrg
389428d7b3dSmrg	/* Wait for the scanline to be outside the region to be copied */
390428d7b3dSmrg	if (scrn->vtSema &&
391428d7b3dSmrg	    pixmap_is_scanout(get_drawable_pixmap(dst)) &&
392428d7b3dSmrg	    intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) {
393428d7b3dSmrg		BoxPtr box;
394428d7b3dSmrg		BoxRec crtcbox;
395428d7b3dSmrg		int y1, y2;
396428d7b3dSmrg		int event, load_scan_lines_pipe;
397428d7b3dSmrg		xf86CrtcPtr crtc;
398428d7b3dSmrg		Bool full_height = FALSE;
399428d7b3dSmrg
400428d7b3dSmrg		box = REGION_EXTENTS(unused, gc->pCompositeClip);
401428d7b3dSmrg		crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox);
402428d7b3dSmrg
403428d7b3dSmrg		/*
404428d7b3dSmrg		 * Make sure the CRTC is valid and this is the real front
405428d7b3dSmrg		 * buffer
406428d7b3dSmrg		 */
407428d7b3dSmrg		if (crtc != NULL && !crtc->rotatedData) {
408428d7b3dSmrg			int pipe = intel_crtc_to_pipe(crtc);
409428d7b3dSmrg
410428d7b3dSmrg			/*
411428d7b3dSmrg			 * Make sure we don't wait for a scanline that will
412428d7b3dSmrg			 * never occur
413428d7b3dSmrg			 */
414428d7b3dSmrg			y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
415428d7b3dSmrg			y2 = (box->y2 <= crtcbox.y2) ?
416428d7b3dSmrg			    box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
417428d7b3dSmrg
418428d7b3dSmrg			if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1))
419428d7b3dSmrg			    full_height = TRUE;
420428d7b3dSmrg
421428d7b3dSmrg			/*
422428d7b3dSmrg			 * Pre-965 doesn't have SVBLANK, so we need a bit
423428d7b3dSmrg			 * of extra time for the blitter to start up and
424428d7b3dSmrg			 * do its job for a full height blit
425428d7b3dSmrg			 */
426428d7b3dSmrg			if (full_height && INTEL_INFO(intel)->gen < 040)
427428d7b3dSmrg			    y2 -= 2;
428428d7b3dSmrg
429428d7b3dSmrg			if (pipe == 0) {
430428d7b3dSmrg				event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
431428d7b3dSmrg				load_scan_lines_pipe =
432428d7b3dSmrg				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
433428d7b3dSmrg				if (full_height && INTEL_INFO(intel)->gen >= 040)
434428d7b3dSmrg				    event = MI_WAIT_FOR_PIPEA_SVBLANK;
435428d7b3dSmrg			} else {
436428d7b3dSmrg				event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
437428d7b3dSmrg				load_scan_lines_pipe =
438428d7b3dSmrg				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
439428d7b3dSmrg				if (full_height && INTEL_INFO(intel)->gen >= 040)
440428d7b3dSmrg				    event = MI_WAIT_FOR_PIPEB_SVBLANK;
441428d7b3dSmrg			}
442428d7b3dSmrg
443428d7b3dSmrg			if (crtc->mode.Flags & V_INTERLACE) {
444428d7b3dSmrg				/* DSL count field lines */
445428d7b3dSmrg				y1 /= 2;
446428d7b3dSmrg				y2 /= 2;
447428d7b3dSmrg			}
448428d7b3dSmrg
449428d7b3dSmrg			BEGIN_BATCH(5);
450428d7b3dSmrg			/*
451428d7b3dSmrg			 * The documentation says that the LOAD_SCAN_LINES
452428d7b3dSmrg			 * command always comes in pairs. Don't ask me why.
453428d7b3dSmrg			 */
454428d7b3dSmrg			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
455428d7b3dSmrg				  load_scan_lines_pipe);
456428d7b3dSmrg			OUT_BATCH((y1 << 16) | (y2-1));
457428d7b3dSmrg			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
458428d7b3dSmrg				  load_scan_lines_pipe);
459428d7b3dSmrg			OUT_BATCH((y1 << 16) | (y2-1));
460428d7b3dSmrg			OUT_BATCH(MI_WAIT_FOR_EVENT | event);
461428d7b3dSmrg			ADVANCE_BATCH();
462428d7b3dSmrg		}
463428d7b3dSmrg	}
464428d7b3dSmrg
465428d7b3dSmrg	/* It's important that this copy gets submitted before the
466428d7b3dSmrg	 * direct rendering client submits rendering for the next
467428d7b3dSmrg	 * frame, but we don't actually need to submit right now.  The
468428d7b3dSmrg	 * client will wait for the DRI2CopyRegion reply or the swap
469428d7b3dSmrg	 * buffer event before rendering, and we'll hit the flush
470428d7b3dSmrg	 * callback chain before those messages are sent.  We submit
471428d7b3dSmrg	 * our batch buffers from the flush callback chain so we know
472428d7b3dSmrg	 * that will happen before the client tries to render
473428d7b3dSmrg	 * again. */
474428d7b3dSmrg
475428d7b3dSmrg	gc->ops->CopyArea(src, dst, gc,
476428d7b3dSmrg			  0, 0,
477428d7b3dSmrg			  drawable->width, drawable->height,
478428d7b3dSmrg			  0, 0);
479428d7b3dSmrg
480428d7b3dSmrg	FreeScratchGC(gc);
481428d7b3dSmrg
482428d7b3dSmrg	/* And make sure the WAIT_FOR_EVENT is queued before any
483428d7b3dSmrg	 * modesetting/dpms operations on the pipe.
484428d7b3dSmrg	 */
485428d7b3dSmrg	intel_batch_submit(scrn);
486428d7b3dSmrg}
487428d7b3dSmrg
488428d7b3dSmrgstatic void
489428d7b3dSmrgI830DRI2FallbackBlitSwap(DrawablePtr drawable,
490428d7b3dSmrg			 DRI2BufferPtr dst,
491428d7b3dSmrg			 DRI2BufferPtr src)
492428d7b3dSmrg{
493428d7b3dSmrg	BoxRec box;
494428d7b3dSmrg	RegionRec region;
495428d7b3dSmrg
496428d7b3dSmrg	box.x1 = 0;
497428d7b3dSmrg	box.y1 = 0;
498428d7b3dSmrg	box.x2 = drawable->width;
499428d7b3dSmrg	box.y2 = drawable->height;
500428d7b3dSmrg	REGION_INIT(pScreen, &region, &box, 0);
501428d7b3dSmrg
502428d7b3dSmrg	I830DRI2CopyRegion(drawable, &region, dst, src);
503428d7b3dSmrg}
504428d7b3dSmrg
505428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4
506428d7b3dSmrg
507428d7b3dSmrgstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
508428d7b3dSmrg{
509428d7b3dSmrg	if (buffer) {
510428d7b3dSmrg		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
511428d7b3dSmrg		private->refcnt++;
512428d7b3dSmrg	}
513428d7b3dSmrg}
514428d7b3dSmrg
515428d7b3dSmrgstatic xf86CrtcPtr
516428d7b3dSmrgI830DRI2DrawableCrtc(DrawablePtr pDraw)
517428d7b3dSmrg{
518428d7b3dSmrg	ScreenPtr pScreen = pDraw->pScreen;
519428d7b3dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
520428d7b3dSmrg	BoxRec box, crtcbox;
521428d7b3dSmrg	xf86CrtcPtr crtc = NULL;
522428d7b3dSmrg
523428d7b3dSmrg	box.x1 = pDraw->x;
524428d7b3dSmrg	box.y1 = pDraw->y;
525428d7b3dSmrg	box.x2 = box.x1 + pDraw->width;
526428d7b3dSmrg	box.y2 = box.y1 + pDraw->height;
527428d7b3dSmrg
528428d7b3dSmrg	if (pDraw->type != DRAWABLE_PIXMAP)
529428d7b3dSmrg		crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
530428d7b3dSmrg
531428d7b3dSmrg	/* Make sure the CRTC is valid and this is the real front buffer */
532428d7b3dSmrg	if (crtc != NULL && !crtc->rotatedData)
533428d7b3dSmrg                return crtc;
534428d7b3dSmrg
535428d7b3dSmrg	return NULL;
536428d7b3dSmrg}
537428d7b3dSmrg
538428d7b3dSmrgstatic RESTYPE	frame_event_client_type, frame_event_drawable_type;
539428d7b3dSmrg
540428d7b3dSmrgstruct i830_dri2_resource {
541428d7b3dSmrg	XID id;
542428d7b3dSmrg	RESTYPE type;
543428d7b3dSmrg	struct list list;
544428d7b3dSmrg};
545428d7b3dSmrg
546428d7b3dSmrgstatic struct i830_dri2_resource *
547428d7b3dSmrgget_resource(XID id, RESTYPE type)
548428d7b3dSmrg{
549428d7b3dSmrg	struct i830_dri2_resource *resource;
550428d7b3dSmrg	void *ptr;
551428d7b3dSmrg
552428d7b3dSmrg	ptr = NULL;
553428d7b3dSmrg	dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
554428d7b3dSmrg	if (ptr)
555428d7b3dSmrg		return ptr;
556428d7b3dSmrg
557428d7b3dSmrg	resource = malloc(sizeof(*resource));
558428d7b3dSmrg	if (resource == NULL)
559428d7b3dSmrg		return NULL;
560428d7b3dSmrg
561428d7b3dSmrg	if (!AddResource(id, type, resource)) {
562428d7b3dSmrg		free(resource);
563428d7b3dSmrg		return NULL;
564428d7b3dSmrg	}
565428d7b3dSmrg
566428d7b3dSmrg	resource->id = id;
567428d7b3dSmrg	resource->type = type;
568428d7b3dSmrg	list_init(&resource->list);
569428d7b3dSmrg	return resource;
570428d7b3dSmrg}
571428d7b3dSmrg
572428d7b3dSmrgstatic int
573428d7b3dSmrgi830_dri2_frame_event_client_gone(void *data, XID id)
574428d7b3dSmrg{
575428d7b3dSmrg	struct i830_dri2_resource *resource = data;
576428d7b3dSmrg
577428d7b3dSmrg	while (!list_is_empty(&resource->list)) {
578428d7b3dSmrg		DRI2FrameEventPtr info =
579428d7b3dSmrg			list_first_entry(&resource->list,
580428d7b3dSmrg					 DRI2FrameEventRec,
581428d7b3dSmrg					 client_resource);
582428d7b3dSmrg
583428d7b3dSmrg		list_del(&info->client_resource);
584428d7b3dSmrg		info->client = NULL;
585428d7b3dSmrg	}
586428d7b3dSmrg	free(resource);
587428d7b3dSmrg
588428d7b3dSmrg	return Success;
589428d7b3dSmrg}
590428d7b3dSmrg
591428d7b3dSmrgstatic int
592428d7b3dSmrgi830_dri2_frame_event_drawable_gone(void *data, XID id)
593428d7b3dSmrg{
594428d7b3dSmrg	struct i830_dri2_resource *resource = data;
595428d7b3dSmrg
596428d7b3dSmrg	while (!list_is_empty(&resource->list)) {
597428d7b3dSmrg		DRI2FrameEventPtr info =
598428d7b3dSmrg			list_first_entry(&resource->list,
599428d7b3dSmrg					 DRI2FrameEventRec,
600428d7b3dSmrg					 drawable_resource);
601428d7b3dSmrg
602428d7b3dSmrg		list_del(&info->drawable_resource);
603428d7b3dSmrg		info->drawable_id = None;
604428d7b3dSmrg	}
605428d7b3dSmrg	free(resource);
606428d7b3dSmrg
607428d7b3dSmrg	return Success;
608428d7b3dSmrg}
609428d7b3dSmrg
610428d7b3dSmrgstatic Bool
611428d7b3dSmrgi830_dri2_register_frame_event_resource_types(void)
612428d7b3dSmrg{
613428d7b3dSmrg	frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client");
614428d7b3dSmrg	if (!frame_event_client_type)
615428d7b3dSmrg		return FALSE;
616428d7b3dSmrg
617428d7b3dSmrg	frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable");
618428d7b3dSmrg	if (!frame_event_drawable_type)
619428d7b3dSmrg		return FALSE;
620428d7b3dSmrg
621428d7b3dSmrg	return TRUE;
622428d7b3dSmrg}
623428d7b3dSmrg
624428d7b3dSmrgstatic XID
625428d7b3dSmrgget_client_id(ClientPtr client)
626428d7b3dSmrg{
627428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY
628428d7b3dSmrg	XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key);
629428d7b3dSmrg#else
630428d7b3dSmrg	XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key);
631428d7b3dSmrg#endif
632428d7b3dSmrg	if (*ptr == 0)
633428d7b3dSmrg		*ptr = FakeClientID(client->index);
634428d7b3dSmrg	return *ptr;
635428d7b3dSmrg}
636428d7b3dSmrg
637428d7b3dSmrg/*
638428d7b3dSmrg * Hook this frame event into the server resource
639428d7b3dSmrg * database so we can clean it up if the drawable or
640428d7b3dSmrg * client exits while the swap is pending
641428d7b3dSmrg */
642428d7b3dSmrgstatic Bool
643428d7b3dSmrgi830_dri2_add_frame_event(DRI2FrameEventPtr info)
644428d7b3dSmrg{
645428d7b3dSmrg	struct i830_dri2_resource *resource;
646428d7b3dSmrg
647428d7b3dSmrg	resource = get_resource(get_client_id(info->client),
648428d7b3dSmrg				frame_event_client_type);
649428d7b3dSmrg	if (resource == NULL)
650428d7b3dSmrg		return FALSE;
651428d7b3dSmrg
652428d7b3dSmrg	list_add(&info->client_resource, &resource->list);
653428d7b3dSmrg
654428d7b3dSmrg	resource = get_resource(info->drawable_id, frame_event_drawable_type);
655428d7b3dSmrg	if (resource == NULL) {
656428d7b3dSmrg		list_del(&info->client_resource);
657428d7b3dSmrg		return FALSE;
658428d7b3dSmrg	}
659428d7b3dSmrg
660428d7b3dSmrg	list_add(&info->drawable_resource, &resource->list);
661428d7b3dSmrg
662428d7b3dSmrg	return TRUE;
663428d7b3dSmrg}
664428d7b3dSmrg
665428d7b3dSmrgstatic void
666428d7b3dSmrgi830_dri2_del_frame_event(DRI2FrameEventPtr info)
667428d7b3dSmrg{
668428d7b3dSmrg	list_del(&info->client_resource);
669428d7b3dSmrg	list_del(&info->drawable_resource);
670428d7b3dSmrg
671428d7b3dSmrg	if (info->front)
672428d7b3dSmrg		I830DRI2DestroyBuffer(NULL, info->front);
673428d7b3dSmrg	if (info->back)
674428d7b3dSmrg		I830DRI2DestroyBuffer(NULL, info->back);
675428d7b3dSmrg
676428d7b3dSmrg	free(info);
677428d7b3dSmrg}
678428d7b3dSmrg
679428d7b3dSmrgstatic struct intel_uxa_pixmap *
680428d7b3dSmrgintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back)
681428d7b3dSmrg{
682428d7b3dSmrg	struct intel_uxa_pixmap *new_front = NULL, *new_back;
683428d7b3dSmrg	RegionRec region;
684428d7b3dSmrg
685428d7b3dSmrg	/* Post damage on the front buffer so that listeners, such
686428d7b3dSmrg	 * as DisplayLink know take a copy and shove it over the USB.
687428d7b3dSmrg	 * also for sw cursors.
688428d7b3dSmrg	 */
689428d7b3dSmrg	region.extents.x1 = region.extents.y1 = 0;
690428d7b3dSmrg	region.extents.x2 = front->drawable.width;
691428d7b3dSmrg	region.extents.y2 = front->drawable.height;
692428d7b3dSmrg	region.data = NULL;
693428d7b3dSmrg	DamageRegionAppend(&front->drawable, &region);
694428d7b3dSmrg
695428d7b3dSmrg	new_front = intel_uxa_get_pixmap_private(back);
696428d7b3dSmrg	new_back = intel_uxa_get_pixmap_private(front);
697428d7b3dSmrg	intel_uxa_set_pixmap_private(front, new_front);
698428d7b3dSmrg	intel_uxa_set_pixmap_private(back, new_back);
699428d7b3dSmrg	new_front->busy = 1;
700428d7b3dSmrg	new_back->busy = -1;
701428d7b3dSmrg
702428d7b3dSmrg	DamageRegionProcessPending(&front->drawable);
703428d7b3dSmrg
704428d7b3dSmrg	return new_front;
705428d7b3dSmrg}
706428d7b3dSmrg
707428d7b3dSmrgstatic void
708428d7b3dSmrgI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
709428d7b3dSmrg{
710428d7b3dSmrg	I830DRI2BufferPrivatePtr front_priv, back_priv;
711428d7b3dSmrg	int tmp;
712428d7b3dSmrg	struct intel_uxa_pixmap *new_front;
713428d7b3dSmrg
714428d7b3dSmrg	front_priv = front->driverPrivate;
715428d7b3dSmrg	back_priv = back->driverPrivate;
716428d7b3dSmrg
717428d7b3dSmrg	/* Swap BO names so DRI works */
718428d7b3dSmrg	tmp = front->name;
719428d7b3dSmrg	front->name = back->name;
720428d7b3dSmrg	back->name = tmp;
721428d7b3dSmrg
722428d7b3dSmrg	/* Swap pixmap bos */
723428d7b3dSmrg	new_front = intel_exchange_pixmap_buffers(intel,
724428d7b3dSmrg						  front_priv->pixmap,
725428d7b3dSmrg						  back_priv->pixmap);
726428d7b3dSmrg	dri_bo_unreference (intel->front_buffer);
727428d7b3dSmrg	intel->front_buffer = new_front->bo;
728428d7b3dSmrg	dri_bo_reference (intel->front_buffer);
729428d7b3dSmrg}
730428d7b3dSmrg
731428d7b3dSmrgstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
732428d7b3dSmrg{
733428d7b3dSmrg	drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
734428d7b3dSmrg	assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
735428d7b3dSmrg	return bo;
736428d7b3dSmrg}
737428d7b3dSmrg
738428d7b3dSmrgstatic void
739428d7b3dSmrgI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
740428d7b3dSmrg{
741428d7b3dSmrg        DRI2FrameEventPtr info = pageflip_data;
742428d7b3dSmrg
743428d7b3dSmrg        I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
744428d7b3dSmrg                                 usec % 1000000,
745428d7b3dSmrg                                 info);
746428d7b3dSmrg}
747428d7b3dSmrg
748428d7b3dSmrgstatic void
749428d7b3dSmrgI830DRI2FlipAbort(void *pageflip_data)
750428d7b3dSmrg{
751428d7b3dSmrg        DRI2FrameEventPtr info = pageflip_data;
752428d7b3dSmrg
753428d7b3dSmrg        i830_dri2_del_frame_event(info);
754428d7b3dSmrg}
755428d7b3dSmrg
756428d7b3dSmrg/*
757428d7b3dSmrg * Our internal swap routine takes care of actually exchanging, blitting, or
758428d7b3dSmrg * flipping buffers as necessary.
759428d7b3dSmrg */
760428d7b3dSmrgstatic Bool
761428d7b3dSmrgI830DRI2ScheduleFlip(struct intel_screen_private *intel,
762428d7b3dSmrg		     DrawablePtr draw,
763428d7b3dSmrg		     DRI2FrameEventPtr info)
764428d7b3dSmrg{
765428d7b3dSmrg	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
766428d7b3dSmrg	drm_intel_bo *new_back, *old_back;
767428d7b3dSmrg	int tmp_name;
768428d7b3dSmrg
769428d7b3dSmrg	if (!intel->use_triple_buffer) {
770428d7b3dSmrg		info->type = DRI2_SWAP;
771428d7b3dSmrg		if (!intel_do_pageflip(intel,
772428d7b3dSmrg				       get_pixmap_bo(priv),
773428d7b3dSmrg				       info->pipe, FALSE, info,
774428d7b3dSmrg                                       I830DRI2FlipComplete,
775428d7b3dSmrg                                       I830DRI2FlipAbort))
776428d7b3dSmrg			return FALSE;
777428d7b3dSmrg
778428d7b3dSmrg		I830DRI2ExchangeBuffers(intel, info->front, info->back);
779428d7b3dSmrg		return TRUE;
780428d7b3dSmrg	}
781428d7b3dSmrg
782428d7b3dSmrg	if (intel->pending_flip[info->pipe]) {
783428d7b3dSmrg		assert(intel->pending_flip[info->pipe]->chain == NULL);
784428d7b3dSmrg		intel->pending_flip[info->pipe]->chain = info;
785428d7b3dSmrg		return TRUE;
786428d7b3dSmrg	}
787428d7b3dSmrg
788428d7b3dSmrg	if (intel->back_buffer == NULL) {
789428d7b3dSmrg		new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
790428d7b3dSmrg					      intel->front_buffer->size, 0);
791428d7b3dSmrg		if (new_back == NULL)
792428d7b3dSmrg			return FALSE;
793428d7b3dSmrg
794428d7b3dSmrg		if (intel->front_tiling != I915_TILING_NONE) {
795428d7b3dSmrg			uint32_t tiling = intel->front_tiling;
796428d7b3dSmrg			drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
797428d7b3dSmrg			if (tiling != intel->front_tiling) {
798428d7b3dSmrg				drm_intel_bo_unreference(new_back);
799428d7b3dSmrg				return FALSE;
800428d7b3dSmrg			}
801428d7b3dSmrg		}
802428d7b3dSmrg
803428d7b3dSmrg		drm_intel_bo_disable_reuse(new_back);
804428d7b3dSmrg		dri_bo_flink(new_back, &intel->back_name);
805428d7b3dSmrg	} else {
806428d7b3dSmrg		new_back = intel->back_buffer;
807428d7b3dSmrg		intel->back_buffer = NULL;
808428d7b3dSmrg	}
809428d7b3dSmrg
810428d7b3dSmrg	old_back = get_pixmap_bo(priv);
811428d7b3dSmrg	if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
812428d7b3dSmrg		intel->back_buffer = new_back;
813428d7b3dSmrg		return FALSE;
814428d7b3dSmrg	}
815428d7b3dSmrg	info->type = DRI2_SWAP_CHAIN;
816428d7b3dSmrg	intel->pending_flip[info->pipe] = info;
817428d7b3dSmrg
818428d7b3dSmrg	priv = info->front->driverPrivate;
819428d7b3dSmrg
820428d7b3dSmrg	/* Exchange the current front-buffer with the fresh bo */
821428d7b3dSmrg
822428d7b3dSmrg	intel->back_buffer = intel->front_buffer;
823428d7b3dSmrg	drm_intel_bo_reference(intel->back_buffer);
824428d7b3dSmrg	intel_set_pixmap_bo(priv->pixmap, new_back);
825428d7b3dSmrg	drm_intel_bo_unreference(new_back);
826428d7b3dSmrg
827428d7b3dSmrg	tmp_name = info->front->name;
828428d7b3dSmrg	info->front->name = intel->back_name;
829428d7b3dSmrg	intel->back_name = tmp_name;
830428d7b3dSmrg
831428d7b3dSmrg	/* Then flip DRI2 pointers and update the screen pixmap */
832428d7b3dSmrg	I830DRI2ExchangeBuffers(intel, info->front, info->back);
833428d7b3dSmrg	DRI2SwapComplete(info->client, draw, 0, 0, 0,
834428d7b3dSmrg			 DRI2_EXCHANGE_COMPLETE,
835428d7b3dSmrg			 info->event_complete,
836428d7b3dSmrg			 info->event_data);
837428d7b3dSmrg	return TRUE;
838428d7b3dSmrg}
839428d7b3dSmrg
840428d7b3dSmrgstatic Bool
841428d7b3dSmrgcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
842428d7b3dSmrg{
843428d7b3dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen);
844428d7b3dSmrg	struct intel_screen_private *intel = intel_get_screen_private(pScrn);
845428d7b3dSmrg	I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
846428d7b3dSmrg	I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
847428d7b3dSmrg	PixmapPtr front_pixmap = front_priv->pixmap;
848428d7b3dSmrg	PixmapPtr back_pixmap = back_priv->pixmap;
849428d7b3dSmrg	struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap);
850428d7b3dSmrg	struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap);
851428d7b3dSmrg
852428d7b3dSmrg	if (!pScrn->vtSema)
853428d7b3dSmrg		return FALSE;
854428d7b3dSmrg
855428d7b3dSmrg	if (I830DRI2DrawableCrtc(drawable) == NULL)
856428d7b3dSmrg		return FALSE;
857428d7b3dSmrg
858428d7b3dSmrg	if (!DRI2CanFlip(drawable))
859428d7b3dSmrg		return FALSE;
860428d7b3dSmrg
861428d7b3dSmrg	if (intel->shadow_present)
862428d7b3dSmrg		return FALSE;
863428d7b3dSmrg
864428d7b3dSmrg	if (!intel->use_pageflipping)
865428d7b3dSmrg		return FALSE;
866428d7b3dSmrg
867428d7b3dSmrg	if (front_pixmap->drawable.width != back_pixmap->drawable.width)
868428d7b3dSmrg		return FALSE;
869428d7b3dSmrg
870428d7b3dSmrg	if (front_pixmap->drawable.height != back_pixmap->drawable.height)
871428d7b3dSmrg		return FALSE;
872428d7b3dSmrg
873428d7b3dSmrg	/* XXX should we be checking depth instead of bpp? */
874428d7b3dSmrg#if 0
875428d7b3dSmrg	if (front_pixmap->drawable.depth != back_pixmap->drawable.depth)
876428d7b3dSmrg		return FALSE;
877428d7b3dSmrg#else
878428d7b3dSmrg	if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
879428d7b3dSmrg		return FALSE;
880428d7b3dSmrg#endif
881428d7b3dSmrg
882428d7b3dSmrg	/* prevent an implicit tiling mode change */
883428d7b3dSmrg	if (front_intel->tiling != back_intel->tiling)
884428d7b3dSmrg		return FALSE;
885428d7b3dSmrg
886428d7b3dSmrg	if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2))
887428d7b3dSmrg		return FALSE;
888428d7b3dSmrg
889428d7b3dSmrg	return TRUE;
890428d7b3dSmrg}
891428d7b3dSmrg
892428d7b3dSmrgvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
893428d7b3dSmrg			       unsigned int tv_usec, DRI2FrameEventPtr swap_info)
894428d7b3dSmrg{
895428d7b3dSmrg	intel_screen_private *intel = swap_info->intel;
896428d7b3dSmrg	DrawablePtr drawable;
897428d7b3dSmrg	int status;
898428d7b3dSmrg
899428d7b3dSmrg	if (!swap_info->drawable_id)
900428d7b3dSmrg		status = BadDrawable;
901428d7b3dSmrg	else
902428d7b3dSmrg		status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
903428d7b3dSmrg					   M_ANY, DixWriteAccess);
904428d7b3dSmrg	if (status != Success) {
905428d7b3dSmrg		i830_dri2_del_frame_event(swap_info);
906428d7b3dSmrg		return;
907428d7b3dSmrg	}
908428d7b3dSmrg
909428d7b3dSmrg
910428d7b3dSmrg	switch (swap_info->type) {
911428d7b3dSmrg	case DRI2_FLIP:
912428d7b3dSmrg		/* If we can still flip... */
913428d7b3dSmrg		if (can_exchange(drawable, swap_info->front, swap_info->back) &&
914428d7b3dSmrg		    I830DRI2ScheduleFlip(intel, drawable, swap_info))
915428d7b3dSmrg			return;
916428d7b3dSmrg
917428d7b3dSmrg		/* else fall through to exchange/blit */
918428d7b3dSmrg	case DRI2_SWAP: {
919428d7b3dSmrg		I830DRI2FallbackBlitSwap(drawable,
920428d7b3dSmrg					 swap_info->front, swap_info->back);
921428d7b3dSmrg		DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
922428d7b3dSmrg				 DRI2_BLIT_COMPLETE,
923428d7b3dSmrg				 swap_info->client ? swap_info->event_complete : NULL,
924428d7b3dSmrg				 swap_info->event_data);
925428d7b3dSmrg		break;
926428d7b3dSmrg	}
927428d7b3dSmrg	case DRI2_WAITMSC:
928428d7b3dSmrg		if (swap_info->client)
929428d7b3dSmrg			DRI2WaitMSCComplete(swap_info->client, drawable,
930428d7b3dSmrg					    frame, tv_sec, tv_usec);
931428d7b3dSmrg		break;
932428d7b3dSmrg	default:
933428d7b3dSmrg		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
934428d7b3dSmrg			   "%s: unknown vblank event received\n", __func__);
935428d7b3dSmrg		/* Unknown type */
936428d7b3dSmrg		break;
937428d7b3dSmrg	}
938428d7b3dSmrg
939428d7b3dSmrg	i830_dri2_del_frame_event(swap_info);
940428d7b3dSmrg}
941428d7b3dSmrg
942428d7b3dSmrgvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
943428d7b3dSmrg			      unsigned int tv_usec, DRI2FrameEventPtr flip_info)
944428d7b3dSmrg{
945428d7b3dSmrg	struct intel_screen_private *intel = flip_info->intel;
946428d7b3dSmrg	DrawablePtr drawable;
947428d7b3dSmrg	DRI2FrameEventPtr chain;
948428d7b3dSmrg
949428d7b3dSmrg	drawable = NULL;
950428d7b3dSmrg	if (flip_info->drawable_id)
951428d7b3dSmrg		dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
952428d7b3dSmrg				  M_ANY, DixWriteAccess);
953428d7b3dSmrg
954428d7b3dSmrg
955428d7b3dSmrg	/* We assume our flips arrive in order, so we don't check the frame */
956428d7b3dSmrg	switch (flip_info->type) {
957428d7b3dSmrg	case DRI2_SWAP:
958428d7b3dSmrg		if (!drawable)
959428d7b3dSmrg			break;
960428d7b3dSmrg
961428d7b3dSmrg		/* Check for too small vblank count of pageflip completion, taking wraparound
962428d7b3dSmrg		 * into account. This usually means some defective kms pageflip completion,
963428d7b3dSmrg		 * causing wrong (msc, ust) return values and possible visual corruption.
964428d7b3dSmrg		 */
965428d7b3dSmrg		if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
966428d7b3dSmrg			static int limit = 5;
967428d7b3dSmrg
968428d7b3dSmrg			/* XXX we are currently hitting this path with older
969428d7b3dSmrg			 * kernels, so make it quieter.
970428d7b3dSmrg			 */
971428d7b3dSmrg			if (limit) {
972428d7b3dSmrg				xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
973428d7b3dSmrg					   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
974428d7b3dSmrg					   __func__, frame, flip_info->frame);
975428d7b3dSmrg				limit--;
976428d7b3dSmrg			}
977428d7b3dSmrg
978428d7b3dSmrg			/* All-0 values signal timestamping failure. */
979428d7b3dSmrg			frame = tv_sec = tv_usec = 0;
980428d7b3dSmrg		}
981428d7b3dSmrg
982428d7b3dSmrg		DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
983428d7b3dSmrg				 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
984428d7b3dSmrg				 flip_info->event_data);
985428d7b3dSmrg		break;
986428d7b3dSmrg
987428d7b3dSmrg	case DRI2_SWAP_CHAIN:
988428d7b3dSmrg		assert(intel->pending_flip[flip_info->pipe] == flip_info);
989428d7b3dSmrg		intel->pending_flip[flip_info->pipe] = NULL;
990428d7b3dSmrg
991428d7b3dSmrg		chain = flip_info->chain;
992428d7b3dSmrg		if (chain) {
993428d7b3dSmrg			DrawablePtr chain_drawable = NULL;
994428d7b3dSmrg			if (chain->drawable_id)
995428d7b3dSmrg				 dixLookupDrawable(&chain_drawable,
996428d7b3dSmrg						   chain->drawable_id,
997428d7b3dSmrg						   serverClient,
998428d7b3dSmrg						   M_ANY, DixWriteAccess);
999428d7b3dSmrg			if (chain_drawable == NULL) {
1000428d7b3dSmrg				i830_dri2_del_frame_event(chain);
1001428d7b3dSmrg			} else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
1002428d7b3dSmrg				   !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
1003428d7b3dSmrg				I830DRI2FallbackBlitSwap(chain_drawable,
1004428d7b3dSmrg							 chain->front,
1005428d7b3dSmrg							 chain->back);
1006428d7b3dSmrg
1007428d7b3dSmrg				DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
1008428d7b3dSmrg						 DRI2_BLIT_COMPLETE,
1009428d7b3dSmrg						 chain->client ? chain->event_complete : NULL,
1010428d7b3dSmrg						 chain->event_data);
1011428d7b3dSmrg				i830_dri2_del_frame_event(chain);
1012428d7b3dSmrg			}
1013428d7b3dSmrg		}
1014428d7b3dSmrg		break;
1015428d7b3dSmrg
1016428d7b3dSmrg	default:
1017428d7b3dSmrg		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
1018428d7b3dSmrg			   "%s: unknown vblank event received\n", __func__);
1019428d7b3dSmrg		/* Unknown type */
1020428d7b3dSmrg		break;
1021428d7b3dSmrg	}
1022428d7b3dSmrg
1023428d7b3dSmrg	i830_dri2_del_frame_event(flip_info);
1024428d7b3dSmrg}
1025428d7b3dSmrg
1026428d7b3dSmrgstatic uint32_t pipe_select(int pipe)
1027428d7b3dSmrg{
1028428d7b3dSmrg	if (pipe > 1)
1029428d7b3dSmrg		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
1030428d7b3dSmrg	else if (pipe > 0)
1031428d7b3dSmrg		return DRM_VBLANK_SECONDARY;
1032428d7b3dSmrg	else
1033428d7b3dSmrg		return 0;
1034428d7b3dSmrg}
1035428d7b3dSmrg
1036428d7b3dSmrgstatic void
1037428d7b3dSmrgintel_dri2_vblank_handler(ScrnInfoPtr scrn,
1038428d7b3dSmrg                          xf86CrtcPtr crtc,
1039428d7b3dSmrg                          uint64_t msc,
1040428d7b3dSmrg                          uint64_t usec,
1041428d7b3dSmrg                          void *data)
1042428d7b3dSmrg{
1043428d7b3dSmrg        DRI2FrameEventPtr swap_info = data;
1044428d7b3dSmrg
1045428d7b3dSmrg        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
1046428d7b3dSmrg}
1047428d7b3dSmrg
1048428d7b3dSmrgstatic void
1049428d7b3dSmrgintel_dri2_vblank_abort(ScrnInfoPtr scrn,
1050428d7b3dSmrg                        xf86CrtcPtr crtc,
1051428d7b3dSmrg                        void *data)
1052428d7b3dSmrg{
1053428d7b3dSmrg        DRI2FrameEventPtr swap_info = data;
1054428d7b3dSmrg
1055428d7b3dSmrg        i830_dri2_del_frame_event(swap_info);
1056428d7b3dSmrg}
1057428d7b3dSmrg
1058428d7b3dSmrg/*
1059428d7b3dSmrg * ScheduleSwap is responsible for requesting a DRM vblank event for the
1060428d7b3dSmrg * appropriate frame.
1061428d7b3dSmrg *
1062428d7b3dSmrg * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
1063428d7b3dSmrg * the vblank requested can simply be the last queued swap frame + the swap
1064428d7b3dSmrg * interval for the drawable.
1065428d7b3dSmrg *
1066428d7b3dSmrg * In the case of a page flip, we request an event for the last queued swap
1067428d7b3dSmrg * frame + swap interval - 1, since we'll need to queue the flip for the frame
1068428d7b3dSmrg * immediately following the received event.
1069428d7b3dSmrg *
1070428d7b3dSmrg * The client will be blocked if it tries to perform further GL commands
1071428d7b3dSmrg * after queueing a swap, though in the Intel case after queueing a flip, the
1072428d7b3dSmrg * client is free to queue more commands; they'll block in the kernel if
1073428d7b3dSmrg * they access buffers busy with the flip.
1074428d7b3dSmrg *
1075428d7b3dSmrg * When the swap is complete, the driver should call into the server so it
1076428d7b3dSmrg * can send any swap complete events that have been requested.
1077428d7b3dSmrg */
1078428d7b3dSmrgstatic int
1079428d7b3dSmrgI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
1080428d7b3dSmrg		     DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
1081428d7b3dSmrg		     CARD64 remainder, DRI2SwapEventPtr func, void *data)
1082428d7b3dSmrg{
1083428d7b3dSmrg	ScreenPtr screen = draw->pScreen;
1084428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1085428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1086428d7b3dSmrg	drmVBlank vbl;
1087428d7b3dSmrg	int ret;
1088428d7b3dSmrg        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1089428d7b3dSmrg        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
1090428d7b3dSmrg        int flip = 0;
1091428d7b3dSmrg	DRI2FrameEventPtr swap_info = NULL;
1092428d7b3dSmrg	enum DRI2FrameEventType swap_type = DRI2_SWAP;
1093428d7b3dSmrg	uint64_t current_msc, current_ust;
1094428d7b3dSmrg        uint64_t request_msc;
1095428d7b3dSmrg        uint32_t seq;
1096428d7b3dSmrg
1097428d7b3dSmrg	/* Drawable not displayed... just complete the swap */
1098428d7b3dSmrg	if (pipe == -1)
1099428d7b3dSmrg	    goto blit_fallback;
1100428d7b3dSmrg
1101428d7b3dSmrg	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
1102428d7b3dSmrg	if (!swap_info)
1103428d7b3dSmrg	    goto blit_fallback;
1104428d7b3dSmrg
1105428d7b3dSmrg	swap_info->intel = intel;
1106428d7b3dSmrg	swap_info->drawable_id = draw->id;
1107428d7b3dSmrg	swap_info->client = client;
1108428d7b3dSmrg	swap_info->event_complete = func;
1109428d7b3dSmrg	swap_info->event_data = data;
1110428d7b3dSmrg	swap_info->front = front;
1111428d7b3dSmrg	swap_info->back = back;
1112428d7b3dSmrg	swap_info->pipe = pipe;
1113428d7b3dSmrg
1114428d7b3dSmrg	if (!i830_dri2_add_frame_event(swap_info)) {
1115428d7b3dSmrg	    free(swap_info);
1116428d7b3dSmrg	    swap_info = NULL;
1117428d7b3dSmrg	    goto blit_fallback;
1118428d7b3dSmrg	}
1119428d7b3dSmrg
1120428d7b3dSmrg	I830DRI2ReferenceBuffer(front);
1121428d7b3dSmrg	I830DRI2ReferenceBuffer(back);
1122428d7b3dSmrg
1123428d7b3dSmrg        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
1124428d7b3dSmrg	if (ret)
1125428d7b3dSmrg	    goto blit_fallback;
1126428d7b3dSmrg
1127428d7b3dSmrg	/* Flips need to be submitted one frame before */
1128428d7b3dSmrg	if (can_exchange(draw, front, back)) {
1129428d7b3dSmrg	    swap_type = DRI2_FLIP;
1130428d7b3dSmrg	    flip = 1;
1131428d7b3dSmrg	}
1132428d7b3dSmrg
1133428d7b3dSmrg	swap_info->type = swap_type;
1134428d7b3dSmrg
1135428d7b3dSmrg	/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
1136428d7b3dSmrg	 * Do it early, so handling of different timing constraints
1137428d7b3dSmrg	 * for divisor, remainder and msc vs. target_msc works.
1138428d7b3dSmrg	 */
1139428d7b3dSmrg	if (*target_msc > 0)
1140428d7b3dSmrg		*target_msc -= flip;
1141428d7b3dSmrg
1142428d7b3dSmrg	/*
1143428d7b3dSmrg	 * If divisor is zero, or current_msc is smaller than target_msc
1144428d7b3dSmrg	 * we just need to make sure target_msc passes before initiating
1145428d7b3dSmrg	 * the swap.
1146428d7b3dSmrg	 */
1147428d7b3dSmrg	if (divisor == 0 || current_msc < *target_msc) {
1148428d7b3dSmrg		/*
1149428d7b3dSmrg		 * If we can, schedule the flip directly from here rather
1150428d7b3dSmrg		 * than waiting for an event from the kernel for the current
1151428d7b3dSmrg		 * (or a past) MSC.
1152428d7b3dSmrg		 */
1153428d7b3dSmrg		if (flip && divisor == 0 && current_msc >= *target_msc &&
1154428d7b3dSmrg		    I830DRI2ScheduleFlip(intel, draw, swap_info))
1155428d7b3dSmrg			return TRUE;
1156428d7b3dSmrg
1157428d7b3dSmrg		vbl.request.type =
1158428d7b3dSmrg			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1159428d7b3dSmrg
1160428d7b3dSmrg		/* If non-pageflipping, but blitting/exchanging, we need to use
1161428d7b3dSmrg		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
1162428d7b3dSmrg		 * on.
1163428d7b3dSmrg		 */
1164428d7b3dSmrg		if (flip == 0)
1165428d7b3dSmrg			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1166428d7b3dSmrg
1167428d7b3dSmrg		/* If target_msc already reached or passed, set it to
1168428d7b3dSmrg		 * current_msc to ensure we return a reasonable value back
1169428d7b3dSmrg		 * to the caller. This makes swap_interval logic more robust.
1170428d7b3dSmrg		 */
1171428d7b3dSmrg		if (current_msc >= *target_msc)
1172428d7b3dSmrg			*target_msc = current_msc;
1173428d7b3dSmrg
1174428d7b3dSmrg                seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1175428d7b3dSmrg                if (!seq)
1176428d7b3dSmrg                        goto blit_fallback;
1177428d7b3dSmrg
1178428d7b3dSmrg		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
1179428d7b3dSmrg		vbl.request.signal = seq;
1180428d7b3dSmrg
1181428d7b3dSmrg		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1182428d7b3dSmrg		if (ret) {
1183428d7b3dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1184428d7b3dSmrg				   "divisor 0 get vblank counter failed: %s\n",
1185428d7b3dSmrg				   strerror(errno));
1186428d7b3dSmrg			goto blit_fallback;
1187428d7b3dSmrg		}
1188428d7b3dSmrg
1189428d7b3dSmrg                *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
1190428d7b3dSmrg		swap_info->frame = *target_msc;
1191428d7b3dSmrg
1192428d7b3dSmrg		return TRUE;
1193428d7b3dSmrg	}
1194428d7b3dSmrg
1195428d7b3dSmrg	/*
1196428d7b3dSmrg	 * If we get here, target_msc has already passed or we don't have one,
1197428d7b3dSmrg	 * and we need to queue an event that will satisfy the divisor/remainder
1198428d7b3dSmrg	 * equation.
1199428d7b3dSmrg	 */
1200428d7b3dSmrg	vbl.request.type =
1201428d7b3dSmrg		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1202428d7b3dSmrg	if (flip == 0)
1203428d7b3dSmrg		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
1204428d7b3dSmrg
1205428d7b3dSmrg        request_msc = current_msc - (current_msc % divisor) +
1206428d7b3dSmrg                remainder;
1207428d7b3dSmrg
1208428d7b3dSmrg	/*
1209428d7b3dSmrg	 * If the calculated deadline vbl.request.sequence is smaller than
1210428d7b3dSmrg	 * or equal to current_msc, it means we've passed the last point
1211428d7b3dSmrg	 * when effective onset frame seq could satisfy
1212428d7b3dSmrg	 * seq % divisor == remainder, so we need to wait for the next time
1213428d7b3dSmrg	 * this will happen.
1214428d7b3dSmrg
1215428d7b3dSmrg	 * This comparison takes the 1 frame swap delay in pageflipping mode
1216428d7b3dSmrg	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
1217428d7b3dSmrg	 * if we are blitting/exchanging instead of flipping.
1218428d7b3dSmrg	 */
1219428d7b3dSmrg	if (request_msc <= current_msc)
1220428d7b3dSmrg		request_msc += divisor;
1221428d7b3dSmrg
1222428d7b3dSmrg        seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1223428d7b3dSmrg        if (!seq)
1224428d7b3dSmrg                goto blit_fallback;
1225428d7b3dSmrg
1226428d7b3dSmrg	/* Account for 1 frame extra pageflip delay if flip > 0 */
1227428d7b3dSmrg        vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
1228428d7b3dSmrg	vbl.request.signal = seq;
1229428d7b3dSmrg
1230428d7b3dSmrg	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1231428d7b3dSmrg	if (ret) {
1232428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1233428d7b3dSmrg			   "final get vblank counter failed: %s\n",
1234428d7b3dSmrg			   strerror(errno));
1235428d7b3dSmrg		goto blit_fallback;
1236428d7b3dSmrg	}
1237428d7b3dSmrg
1238428d7b3dSmrg	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
1239428d7b3dSmrg	*target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
1240428d7b3dSmrg	swap_info->frame = *target_msc;
1241428d7b3dSmrg
1242428d7b3dSmrg	return TRUE;
1243428d7b3dSmrg
1244428d7b3dSmrgblit_fallback:
1245428d7b3dSmrg	I830DRI2FallbackBlitSwap(draw, front, back);
1246428d7b3dSmrg	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
1247428d7b3dSmrg	if (swap_info)
1248428d7b3dSmrg	    i830_dri2_del_frame_event(swap_info);
1249428d7b3dSmrg	*target_msc = 0; /* offscreen, so zero out target vblank count */
1250428d7b3dSmrg	return TRUE;
1251428d7b3dSmrg}
1252428d7b3dSmrg
1253428d7b3dSmrgstatic uint64_t gettime_us(void)
1254428d7b3dSmrg{
1255428d7b3dSmrg	struct timespec tv;
1256428d7b3dSmrg
1257428d7b3dSmrg	if (clock_gettime(CLOCK_MONOTONIC, &tv))
1258428d7b3dSmrg		return 0;
1259428d7b3dSmrg
1260428d7b3dSmrg	return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
1261428d7b3dSmrg}
1262428d7b3dSmrg
1263428d7b3dSmrg/*
1264428d7b3dSmrg * Get current frame count and frame count timestamp, based on drawable's
1265428d7b3dSmrg * crtc.
1266428d7b3dSmrg */
1267428d7b3dSmrgstatic int
1268428d7b3dSmrgI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
1269428d7b3dSmrg{
1270428d7b3dSmrg	ScreenPtr screen = draw->pScreen;
1271428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1272428d7b3dSmrg	int ret;
1273428d7b3dSmrg        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1274428d7b3dSmrg
1275428d7b3dSmrg	/* Drawable not displayed, make up a *monotonic* value */
1276428d7b3dSmrg	if (crtc == NULL) {
1277428d7b3dSmrgfail:
1278428d7b3dSmrg		*ust = gettime_us();
1279428d7b3dSmrg		*msc = 0;
1280428d7b3dSmrg		return TRUE;
1281428d7b3dSmrg	}
1282428d7b3dSmrg
1283428d7b3dSmrg        ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
1284428d7b3dSmrg	if (ret) {
1285428d7b3dSmrg		static int limit = 5;
1286428d7b3dSmrg		if (limit) {
1287428d7b3dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1288428d7b3dSmrg				   "%s:%d get vblank counter failed: %s\n",
1289428d7b3dSmrg				   __FUNCTION__, __LINE__,
1290428d7b3dSmrg				   strerror(errno));
1291428d7b3dSmrg			limit--;
1292428d7b3dSmrg		}
1293428d7b3dSmrg		goto fail;
1294428d7b3dSmrg	}
1295428d7b3dSmrg
1296428d7b3dSmrg	return TRUE;
1297428d7b3dSmrg}
1298428d7b3dSmrg
1299428d7b3dSmrg/*
1300428d7b3dSmrg * Request a DRM event when the requested conditions will be satisfied.
1301428d7b3dSmrg *
1302428d7b3dSmrg * We need to handle the event and ask the server to wake up the client when
1303428d7b3dSmrg * we receive it.
1304428d7b3dSmrg */
1305428d7b3dSmrgstatic int
1306428d7b3dSmrgI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
1307428d7b3dSmrg			CARD64 divisor, CARD64 remainder)
1308428d7b3dSmrg{
1309428d7b3dSmrg	ScreenPtr screen = draw->pScreen;
1310428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1311428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1312428d7b3dSmrg	DRI2FrameEventPtr wait_info;
1313428d7b3dSmrg	drmVBlank vbl;
1314428d7b3dSmrg	int ret;
1315428d7b3dSmrg        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
1316428d7b3dSmrg        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
1317428d7b3dSmrg	CARD64 current_msc, current_ust, request_msc;
1318428d7b3dSmrg        uint32_t seq;
1319428d7b3dSmrg
1320428d7b3dSmrg	/* Drawable not visible, return immediately */
1321428d7b3dSmrg	if (pipe == -1)
1322428d7b3dSmrg		goto out_complete;
1323428d7b3dSmrg
1324428d7b3dSmrg	wait_info = calloc(1, sizeof(DRI2FrameEventRec));
1325428d7b3dSmrg	if (!wait_info)
1326428d7b3dSmrg		goto out_complete;
1327428d7b3dSmrg
1328428d7b3dSmrg	wait_info->intel = intel;
1329428d7b3dSmrg	wait_info->drawable_id = draw->id;
1330428d7b3dSmrg	wait_info->client = client;
1331428d7b3dSmrg	wait_info->type = DRI2_WAITMSC;
1332428d7b3dSmrg
1333428d7b3dSmrg	if (!i830_dri2_add_frame_event(wait_info)) {
1334428d7b3dSmrg	    free(wait_info);
1335428d7b3dSmrg	    wait_info = NULL;
1336428d7b3dSmrg	    goto out_complete;
1337428d7b3dSmrg	}
1338428d7b3dSmrg
1339428d7b3dSmrg	/* Get current count */
1340428d7b3dSmrg        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
1341428d7b3dSmrg	if (ret)
1342428d7b3dSmrg	    goto out_free;
1343428d7b3dSmrg
1344428d7b3dSmrg	/*
1345428d7b3dSmrg	 * If divisor is zero, or current_msc is smaller than target_msc,
1346428d7b3dSmrg	 * we just need to make sure target_msc passes  before waking up the
1347428d7b3dSmrg	 * client.
1348428d7b3dSmrg	 */
1349428d7b3dSmrg	if (divisor == 0 || current_msc < target_msc) {
1350428d7b3dSmrg		/* If target_msc already reached or passed, set it to
1351428d7b3dSmrg		 * current_msc to ensure we return a reasonable value back
1352428d7b3dSmrg		 * to the caller. This keeps the client from continually
1353428d7b3dSmrg		 * sending us MSC targets from the past by forcibly updating
1354428d7b3dSmrg		 * their count on this call.
1355428d7b3dSmrg		 */
1356428d7b3dSmrg                seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1357428d7b3dSmrg                if (!seq)
1358428d7b3dSmrg                        goto out_free;
1359428d7b3dSmrg
1360428d7b3dSmrg		if (current_msc >= target_msc)
1361428d7b3dSmrg			target_msc = current_msc;
1362428d7b3dSmrg		vbl.request.type =
1363428d7b3dSmrg			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1364428d7b3dSmrg		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
1365428d7b3dSmrg		vbl.request.signal = seq;
1366428d7b3dSmrg
1367428d7b3dSmrg		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1368428d7b3dSmrg		if (ret) {
1369428d7b3dSmrg			static int limit = 5;
1370428d7b3dSmrg			if (limit) {
1371428d7b3dSmrg				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1372428d7b3dSmrg					   "%s:%d get vblank counter failed: %s\n",
1373428d7b3dSmrg					   __FUNCTION__, __LINE__,
1374428d7b3dSmrg					   strerror(errno));
1375428d7b3dSmrg				limit--;
1376428d7b3dSmrg			}
1377428d7b3dSmrg			goto out_free;
1378428d7b3dSmrg		}
1379428d7b3dSmrg
1380428d7b3dSmrg		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
1381428d7b3dSmrg		DRI2BlockClient(client, draw);
1382428d7b3dSmrg		return TRUE;
1383428d7b3dSmrg	}
1384428d7b3dSmrg
1385428d7b3dSmrg	/*
1386428d7b3dSmrg	 * If we get here, target_msc has already passed or we don't have one,
1387428d7b3dSmrg	 * so we queue an event that will satisfy the divisor/remainder equation.
1388428d7b3dSmrg	 */
1389428d7b3dSmrg	vbl.request.type =
1390428d7b3dSmrg		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
1391428d7b3dSmrg
1392428d7b3dSmrg        request_msc = current_msc - (current_msc % divisor) +
1393428d7b3dSmrg                remainder;
1394428d7b3dSmrg	/*
1395428d7b3dSmrg	 * If calculated remainder is larger than requested remainder,
1396428d7b3dSmrg	 * it means we've passed the last point where
1397428d7b3dSmrg	 * seq % divisor == remainder, so we need to wait for the next time
1398428d7b3dSmrg	 * that will happen.
1399428d7b3dSmrg	 */
1400428d7b3dSmrg	if ((current_msc % divisor) >= remainder)
1401428d7b3dSmrg                request_msc += divisor;
1402428d7b3dSmrg
1403428d7b3dSmrg        seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
1404428d7b3dSmrg        if (!seq)
1405428d7b3dSmrg                goto out_free;
1406428d7b3dSmrg
1407428d7b3dSmrg	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
1408428d7b3dSmrg	vbl.request.signal = seq;
1409428d7b3dSmrg
1410428d7b3dSmrg	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
1411428d7b3dSmrg	if (ret) {
1412428d7b3dSmrg		static int limit = 5;
1413428d7b3dSmrg		if (limit) {
1414428d7b3dSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1415428d7b3dSmrg				   "%s:%d get vblank counter failed: %s\n",
1416428d7b3dSmrg				   __FUNCTION__, __LINE__,
1417428d7b3dSmrg				   strerror(errno));
1418428d7b3dSmrg			limit--;
1419428d7b3dSmrg		}
1420428d7b3dSmrg		goto out_free;
1421428d7b3dSmrg	}
1422428d7b3dSmrg
1423428d7b3dSmrg	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
1424428d7b3dSmrg	DRI2BlockClient(client, draw);
1425428d7b3dSmrg
1426428d7b3dSmrg	return TRUE;
1427428d7b3dSmrg
1428428d7b3dSmrgout_free:
1429428d7b3dSmrg	i830_dri2_del_frame_event(wait_info);
1430428d7b3dSmrgout_complete:
1431428d7b3dSmrg	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
1432428d7b3dSmrg	return TRUE;
1433428d7b3dSmrg}
1434428d7b3dSmrg
1435428d7b3dSmrgstatic int dri2_server_generation;
1436428d7b3dSmrg#endif
1437428d7b3dSmrg
1438428d7b3dSmrgstatic int has_i830_dri(void)
1439428d7b3dSmrg{
1440428d7b3dSmrg	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
1441428d7b3dSmrg}
1442428d7b3dSmrg
1443428d7b3dSmrgstatic const char *dri_driver_name(intel_screen_private *intel)
1444428d7b3dSmrg{
1445428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
1446428d7b3dSmrg	const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
1447428d7b3dSmrg	Bool dummy;
1448428d7b3dSmrg
1449428d7b3dSmrg	if (s == NULL || xf86getBoolValue(&dummy, s)) {
1450428d7b3dSmrg		if (INTEL_INFO(intel)->gen < 030)
1451428d7b3dSmrg			return has_i830_dri() ? "i830" : "i915";
1452428d7b3dSmrg		else if (INTEL_INFO(intel)->gen < 040)
1453428d7b3dSmrg			return "i915";
1454428d7b3dSmrg		else
1455428d7b3dSmrg			return "i965";
1456428d7b3dSmrg	}
1457428d7b3dSmrg
1458428d7b3dSmrg	return s;
1459428d7b3dSmrg#else
1460428d7b3dSmrg	if (INTEL_INFO(intel)->gen < 030)
1461428d7b3dSmrg		return has_i830_dri() ? "i830" : "i915";
1462428d7b3dSmrg	else if (INTEL_INFO(intel)->gen < 040)
1463428d7b3dSmrg		return "i915";
1464428d7b3dSmrg	else
1465428d7b3dSmrg		return "i965";
1466428d7b3dSmrg#endif
1467428d7b3dSmrg}
1468428d7b3dSmrg
1469428d7b3dSmrgBool I830DRI2ScreenInit(ScreenPtr screen)
1470428d7b3dSmrg{
1471428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1472428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1473428d7b3dSmrg	DRI2InfoRec info;
1474428d7b3dSmrg	int dri2scr_major = 1;
1475428d7b3dSmrg	int dri2scr_minor = 0;
1476428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4
1477428d7b3dSmrg	const char *driverNames[2];
1478428d7b3dSmrg#endif
1479428d7b3dSmrg
1480428d7b3dSmrg	if (intel->force_fallback) {
1481428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1482428d7b3dSmrg			   "cannot enable DRI2 whilst forcing software fallbacks\n");
1483428d7b3dSmrg		return FALSE;
1484428d7b3dSmrg	}
1485428d7b3dSmrg
1486428d7b3dSmrg	if (xf86LoaderCheckSymbol("DRI2Version"))
1487428d7b3dSmrg		DRI2Version(&dri2scr_major, &dri2scr_minor);
1488428d7b3dSmrg
1489428d7b3dSmrg	if (dri2scr_minor < 1) {
1490428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1491428d7b3dSmrg			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
1492428d7b3dSmrg		return FALSE;
1493428d7b3dSmrg	}
1494428d7b3dSmrg
1495428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY
1496428d7b3dSmrg	if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID)))
1497428d7b3dSmrg		return FALSE;
1498428d7b3dSmrg#else
1499428d7b3dSmrg	if (!dixRequestPrivate(&i830_client_key, sizeof(XID)))
1500428d7b3dSmrg		return FALSE;
1501428d7b3dSmrg#endif
1502428d7b3dSmrg
1503428d7b3dSmrg
1504428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4
1505428d7b3dSmrg	if (serverGeneration != dri2_server_generation) {
1506428d7b3dSmrg	    dri2_server_generation = serverGeneration;
1507428d7b3dSmrg	    if (!i830_dri2_register_frame_event_resource_types()) {
1508428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1509428d7b3dSmrg			   "Cannot register DRI2 frame event resources\n");
1510428d7b3dSmrg		return FALSE;
1511428d7b3dSmrg	    }
1512428d7b3dSmrg	}
1513428d7b3dSmrg#endif
1514428d7b3dSmrg
1515428d7b3dSmrg	intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD);
1516428d7b3dSmrg	memset(&info, '\0', sizeof(info));
1517428d7b3dSmrg	info.fd = intel->drmSubFD;
1518428d7b3dSmrg	info.driverName = dri_driver_name(intel);
1519428d7b3dSmrg	info.deviceName = intel->deviceName;
1520428d7b3dSmrg
1521428d7b3dSmrg#if DRI2INFOREC_VERSION == 1
1522428d7b3dSmrg	info.version = 1;
1523428d7b3dSmrg	info.CreateBuffers = I830DRI2CreateBuffers;
1524428d7b3dSmrg	info.DestroyBuffers = I830DRI2DestroyBuffers;
1525428d7b3dSmrg#elif DRI2INFOREC_VERSION == 2
1526428d7b3dSmrg	/* The ABI between 2 and 3 was broken so we could get rid of
1527428d7b3dSmrg	 * the multi-buffer alloc functions.  Make sure we indicate the
1528428d7b3dSmrg	 * right version so DRI2 can reject us if it's version 3 or above. */
1529428d7b3dSmrg	info.version = 2;
1530428d7b3dSmrg	info.CreateBuffer = I830DRI2CreateBuffer;
1531428d7b3dSmrg	info.DestroyBuffer = I830DRI2DestroyBuffer;
1532428d7b3dSmrg#else
1533428d7b3dSmrg	info.version = 3;
1534428d7b3dSmrg	info.CreateBuffer = I830DRI2CreateBuffer;
1535428d7b3dSmrg	info.DestroyBuffer = I830DRI2DestroyBuffer;
1536428d7b3dSmrg#endif
1537428d7b3dSmrg
1538428d7b3dSmrg	info.CopyRegion = I830DRI2CopyRegion;
1539428d7b3dSmrg#if DRI2INFOREC_VERSION >= 4
1540428d7b3dSmrg	info.version = 4;
1541428d7b3dSmrg	info.ScheduleSwap = I830DRI2ScheduleSwap;
1542428d7b3dSmrg	info.GetMSC = I830DRI2GetMSC;
1543428d7b3dSmrg	info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
1544428d7b3dSmrg	info.numDrivers = 2;
1545428d7b3dSmrg	info.driverNames = driverNames;
1546428d7b3dSmrg	driverNames[0] = info.driverName;
1547428d7b3dSmrg	driverNames[1] = info.driverName;
1548428d7b3dSmrg#endif
1549428d7b3dSmrg
1550428d7b3dSmrg	return DRI2ScreenInit(screen, &info);
1551428d7b3dSmrg}
1552428d7b3dSmrg
1553428d7b3dSmrgvoid I830DRI2CloseScreen(ScreenPtr screen)
1554428d7b3dSmrg{
1555428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1556428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1557428d7b3dSmrg
1558428d7b3dSmrg	DRI2CloseScreen(screen);
1559428d7b3dSmrg	drmFree(intel->deviceName);
1560428d7b3dSmrg}
1561