intel_dri.c revision 13496ba1
103b705cfSriastradh/**************************************************************************
203b705cfSriastradh
303b705cfSriastradhCopyright 2001 VA Linux Systems Inc., Fremont, California.
403b705cfSriastradhCopyright © 2002 by David Dawes
503b705cfSriastradh
603b705cfSriastradhAll Rights Reserved.
703b705cfSriastradh
803b705cfSriastradhPermission is hereby granted, free of charge, to any person obtaining a
903b705cfSriastradhcopy of this software and associated documentation files (the "Software"),
1003b705cfSriastradhto deal in the Software without restriction, including without limitation
1103b705cfSriastradhon the rights to use, copy, modify, merge, publish, distribute, sub
1203b705cfSriastradhlicense, and/or sell copies of the Software, and to permit persons to whom
1303b705cfSriastradhthe Software is furnished to do so, subject to the following conditions:
1403b705cfSriastradh
1503b705cfSriastradhThe above copyright notice and this permission notice (including the next
1603b705cfSriastradhparagraph) shall be included in all copies or substantial portions of the
1703b705cfSriastradhSoftware.
1803b705cfSriastradh
1903b705cfSriastradhTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2003b705cfSriastradhIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2103b705cfSriastradhFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
2203b705cfSriastradhATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
2303b705cfSriastradhDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2403b705cfSriastradhOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2503b705cfSriastradhUSE OR OTHER DEALINGS IN THE SOFTWARE.
2603b705cfSriastradh
2703b705cfSriastradh**************************************************************************/
2803b705cfSriastradh
2903b705cfSriastradh/*
3003b705cfSriastradh * Authors: Jeff Hartmann <jhartmann@valinux.com>
3103b705cfSriastradh *          David Dawes <dawes@xfree86.org>
3203b705cfSriastradh *          Keith Whitwell <keith@tungstengraphics.com>
3303b705cfSriastradh */
3403b705cfSriastradh
3503b705cfSriastradh#ifdef HAVE_CONFIG_H
3603b705cfSriastradh#include "config.h"
3703b705cfSriastradh#endif
3803b705cfSriastradh
3903b705cfSriastradh#include <stdio.h>
4003b705cfSriastradh#include <string.h>
4103b705cfSriastradh#include <assert.h>
4203b705cfSriastradh#include <sys/types.h>
4303b705cfSriastradh#include <sys/stat.h>
4403b705cfSriastradh#include <sys/ioctl.h>
4503b705cfSriastradh#include <unistd.h>
4603b705cfSriastradh#include <fcntl.h>
4703b705cfSriastradh#include <sys/time.h>
4803b705cfSriastradh#include <time.h>
4903b705cfSriastradh#include <errno.h>
5003b705cfSriastradh
5142542f5fSchristos#include "xorg-server.h"
5203b705cfSriastradh#include "xf86.h"
5303b705cfSriastradh#include "xf86_OSproc.h"
5403b705cfSriastradh
5503b705cfSriastradh#include "xf86Pci.h"
5603b705cfSriastradh#include "xf86drm.h"
5703b705cfSriastradh
5803b705cfSriastradh#include "windowstr.h"
5903b705cfSriastradh#include "shadow.h"
6003b705cfSriastradh#include "fb.h"
6103b705cfSriastradh
6203b705cfSriastradh#include "intel.h"
6303b705cfSriastradh#include "i830_reg.h"
6403b705cfSriastradh
6503b705cfSriastradh#include "i915_drm.h"
6603b705cfSriastradh
6703b705cfSriastradh#include "dri2.h"
6803b705cfSriastradh
6913496ba1Ssnj#if USE_UXA
7013496ba1Ssnj#include "intel_uxa.h"
7113496ba1Ssnj#endif
7203b705cfSriastradh
7303b705cfSriastradhtypedef struct {
7403b705cfSriastradh	int refcnt;
7503b705cfSriastradh	PixmapPtr pixmap;
7603b705cfSriastradh} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
7703b705cfSriastradh
7803b705cfSriastradh#if HAS_DEVPRIVATEKEYREC
7903b705cfSriastradhstatic DevPrivateKeyRec i830_client_key;
8003b705cfSriastradh#else
8103b705cfSriastradhstatic int i830_client_key;
8203b705cfSriastradh#endif
8303b705cfSriastradh
8403b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap)
8503b705cfSriastradh{
8613496ba1Ssnj	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
8703b705cfSriastradh	uint32_t name;
8803b705cfSriastradh
8903b705cfSriastradh	if (priv == NULL || priv->bo == NULL)
9003b705cfSriastradh		return 0;
9103b705cfSriastradh
9203b705cfSriastradh	if (dri_bo_flink(priv->bo, &name) != 0)
9303b705cfSriastradh		return 0;
9403b705cfSriastradh
9542542f5fSchristos	priv->pinned |= PIN_DRI2;
9603b705cfSriastradh	return name;
9703b705cfSriastradh}
9803b705cfSriastradh
9903b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable)
10003b705cfSriastradh{
10103b705cfSriastradh	PixmapPtr pixmap;
10203b705cfSriastradh
10303b705cfSriastradh	pixmap = get_drawable_pixmap(drawable);
10403b705cfSriastradh	if (!intel_get_pixmap_bo(pixmap))
10503b705cfSriastradh		return NULL;
10603b705cfSriastradh
10703b705cfSriastradh	pixmap->refcnt++;
10803b705cfSriastradh	return pixmap;
10903b705cfSriastradh}
11003b705cfSriastradh
11103b705cfSriastradh#if DRI2INFOREC_VERSION < 2
11203b705cfSriastradhstatic DRI2BufferPtr
11303b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
11403b705cfSriastradh		      int count)
11503b705cfSriastradh{
11603b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
11703b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
11803b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
11903b705cfSriastradh	DRI2BufferPtr buffers;
12003b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
12103b705cfSriastradh	PixmapPtr pixmap, pDepthPixmap;
12203b705cfSriastradh	int i;
12303b705cfSriastradh
12403b705cfSriastradh	buffers = calloc(count, sizeof *buffers);
12503b705cfSriastradh	if (buffers == NULL)
12603b705cfSriastradh		return NULL;
12703b705cfSriastradh	privates = calloc(count, sizeof *privates);
12803b705cfSriastradh	if (privates == NULL) {
12903b705cfSriastradh		free(buffers);
13003b705cfSriastradh		return NULL;
13103b705cfSriastradh	}
13203b705cfSriastradh
13303b705cfSriastradh	pDepthPixmap = NULL;
13403b705cfSriastradh	for (i = 0; i < count; i++) {
13503b705cfSriastradh		pixmap = NULL;
13603b705cfSriastradh		if (attachments[i] == DRI2BufferFrontLeft) {
13703b705cfSriastradh			pixmap = get_front_buffer(drawable);
13803b705cfSriastradh
13913496ba1Ssnj			if (pixmap == NULL)
14003b705cfSriastradh				drawable = &(get_drawable_pixmap(drawable)->drawable);
14103b705cfSriastradh		} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
14203b705cfSriastradh			pixmap = pDepthPixmap;
14303b705cfSriastradh			pixmap->refcnt++;
14403b705cfSriastradh		}
14503b705cfSriastradh
14603b705cfSriastradh		if (pixmap == NULL) {
14703b705cfSriastradh			unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
14803b705cfSriastradh
14903b705cfSriastradh			if (intel->tiling & INTEL_TILING_3D) {
15003b705cfSriastradh				switch (attachments[i]) {
15103b705cfSriastradh				case DRI2BufferDepth:
15203b705cfSriastradh					if (SUPPORTS_YTILING(intel))
15303b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_Y;
15403b705cfSriastradh					else
15503b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_X;
15603b705cfSriastradh					break;
15703b705cfSriastradh				case DRI2BufferFakeFrontLeft:
15803b705cfSriastradh				case DRI2BufferFakeFrontRight:
15903b705cfSriastradh				case DRI2BufferBackLeft:
16003b705cfSriastradh				case DRI2BufferBackRight:
16103b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_X;
16203b705cfSriastradh					break;
16303b705cfSriastradh				}
16403b705cfSriastradh			}
16503b705cfSriastradh
16603b705cfSriastradh			pixmap = screen->CreatePixmap(screen,
16703b705cfSriastradh						      drawable->width,
16803b705cfSriastradh						      drawable->height,
16903b705cfSriastradh						      drawable->depth,
17003b705cfSriastradh						      hint);
17103b705cfSriastradh			if (pixmap == NULL ||
17203b705cfSriastradh			    intel_get_pixmap_bo(pixmap) == NULL)
17303b705cfSriastradh			{
17403b705cfSriastradh				if (pixmap)
17503b705cfSriastradh					screen->DestroyPixmap(pixmap);
17603b705cfSriastradh				goto unwind;
17703b705cfSriastradh			}
17803b705cfSriastradh		}
17903b705cfSriastradh
18003b705cfSriastradh		if (attachments[i] == DRI2BufferDepth)
18103b705cfSriastradh			pDepthPixmap = pixmap;
18203b705cfSriastradh
18303b705cfSriastradh		buffers[i].attachment = attachments[i];
18403b705cfSriastradh		buffers[i].pitch = pixmap->devKind;
18503b705cfSriastradh		buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
18603b705cfSriastradh		buffers[i].driverPrivate = &privates[i];
18703b705cfSriastradh		buffers[i].flags = 0;	/* not tiled */
18803b705cfSriastradh		privates[i].refcnt = 1;
18903b705cfSriastradh		privates[i].pixmap = pixmap;
19003b705cfSriastradh
19103b705cfSriastradh		if ((buffers[i].name = pixmap_flink(pixmap)) == 0) {
19203b705cfSriastradh			/* failed to name buffer */
19303b705cfSriastradh			screen->DestroyPixmap(pixmap);
19403b705cfSriastradh			goto unwind;
19503b705cfSriastradh		}
19603b705cfSriastradh	}
19703b705cfSriastradh
19803b705cfSriastradh	return buffers;
19903b705cfSriastradh
20003b705cfSriastradhunwind:
20103b705cfSriastradh	while (i--)
20203b705cfSriastradh		screen->DestroyPixmap(privates[i].pixmap);
20303b705cfSriastradh	free(privates);
20403b705cfSriastradh	free(buffers);
20503b705cfSriastradh	return NULL;
20603b705cfSriastradh}
20703b705cfSriastradh
20803b705cfSriastradhstatic void
20903b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
21003b705cfSriastradh{
21103b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
21203b705cfSriastradh	I830DRI2BufferPrivatePtr private;
21303b705cfSriastradh	int i;
21403b705cfSriastradh
21503b705cfSriastradh	for (i = 0; i < count; i++) {
21603b705cfSriastradh		private = buffers[i].driverPrivate;
21703b705cfSriastradh		screen->DestroyPixmap(private->pixmap);
21803b705cfSriastradh	}
21903b705cfSriastradh
22003b705cfSriastradh	if (buffers) {
22103b705cfSriastradh		free(buffers[0].driverPrivate);
22203b705cfSriastradh		free(buffers);
22303b705cfSriastradh	}
22403b705cfSriastradh}
22503b705cfSriastradh
22603b705cfSriastradh#else
22703b705cfSriastradh
22803b705cfSriastradhstatic DRI2Buffer2Ptr
22903b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
23003b705cfSriastradh		     unsigned int format)
23103b705cfSriastradh{
23203b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
23303b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
23403b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
23503b705cfSriastradh	DRI2Buffer2Ptr buffer;
23603b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
23703b705cfSriastradh	PixmapPtr pixmap;
23803b705cfSriastradh
23903b705cfSriastradh	buffer = calloc(1, sizeof *buffer);
24003b705cfSriastradh	if (buffer == NULL)
24103b705cfSriastradh		return NULL;
24203b705cfSriastradh	privates = calloc(1, sizeof *privates);
24303b705cfSriastradh	if (privates == NULL) {
24403b705cfSriastradh		free(buffer);
24503b705cfSriastradh		return NULL;
24603b705cfSriastradh	}
24703b705cfSriastradh
24803b705cfSriastradh	pixmap = NULL;
24903b705cfSriastradh	if (attachment == DRI2BufferFrontLeft) {
25003b705cfSriastradh		pixmap = get_front_buffer(drawable);
25113496ba1Ssnj		if (pixmap == NULL)
25203b705cfSriastradh			drawable = &(get_drawable_pixmap(drawable)->drawable);
25303b705cfSriastradh	}
25403b705cfSriastradh
25503b705cfSriastradh	if (pixmap == NULL) {
25603b705cfSriastradh		unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
25703b705cfSriastradh		int pixmap_width = drawable->width;
25803b705cfSriastradh		int pixmap_height = drawable->height;
25903b705cfSriastradh		int pixmap_cpp = (format != 0) ? format : drawable->depth;
26003b705cfSriastradh
26103b705cfSriastradh		if (intel->tiling & INTEL_TILING_3D) {
26203b705cfSriastradh			switch (attachment) {
26303b705cfSriastradh			case DRI2BufferDepth:
26403b705cfSriastradh			case DRI2BufferDepthStencil:
26503b705cfSriastradh			case DRI2BufferHiz:
26603b705cfSriastradh				if (SUPPORTS_YTILING(intel)) {
26703b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_Y;
26803b705cfSriastradh					break;
26903b705cfSriastradh				}
27003b705cfSriastradh			case DRI2BufferAccum:
27103b705cfSriastradh			case DRI2BufferBackLeft:
27203b705cfSriastradh			case DRI2BufferBackRight:
27303b705cfSriastradh			case DRI2BufferFakeFrontLeft:
27403b705cfSriastradh			case DRI2BufferFakeFrontRight:
27503b705cfSriastradh			case DRI2BufferFrontLeft:
27603b705cfSriastradh			case DRI2BufferFrontRight:
27703b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_X;
27803b705cfSriastradh				break;
27903b705cfSriastradh			case DRI2BufferStencil:
28003b705cfSriastradh				/*
28103b705cfSriastradh				 * The stencil buffer is W tiled. However, we
28203b705cfSriastradh				 * request from the kernel a non-tiled buffer
28303b705cfSriastradh				 * because the GTT is incapable of W fencing.
28403b705cfSriastradh				 */
28503b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_NONE;
28603b705cfSriastradh				break;
28703b705cfSriastradh			default:
28803b705cfSriastradh				free(privates);
28903b705cfSriastradh				free(buffer);
29003b705cfSriastradh				return NULL;
29103b705cfSriastradh                        }
29203b705cfSriastradh		}
29303b705cfSriastradh
29403b705cfSriastradh		/*
29503b705cfSriastradh		 * The stencil buffer has quirky pitch requirements.  From Vol
29603b705cfSriastradh		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
29703b705cfSriastradh		 * Pitch":
29803b705cfSriastradh		 *    The pitch must be set to 2x the value computed based on
29903b705cfSriastradh		 *    width, as the stencil buffer is stored with two rows
30003b705cfSriastradh		 *    interleaved.
30103b705cfSriastradh		 * To accomplish this, we resort to the nasty hack of doubling
30203b705cfSriastradh		 * the drm region's cpp and halving its height.
30303b705cfSriastradh		 *
30403b705cfSriastradh		 * If we neglect to double the pitch, then render corruption
30503b705cfSriastradh		 * occurs.
30603b705cfSriastradh		 */
30703b705cfSriastradh		if (attachment == DRI2BufferStencil) {
30803b705cfSriastradh			pixmap_width = ALIGN(pixmap_width, 64);
30903b705cfSriastradh			pixmap_height = ALIGN((pixmap_height + 1) / 2, 64);
31003b705cfSriastradh			pixmap_cpp *= 2;
31103b705cfSriastradh		}
31203b705cfSriastradh
31303b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
31403b705cfSriastradh					      pixmap_width,
31503b705cfSriastradh					      pixmap_height,
31603b705cfSriastradh					      pixmap_cpp,
31703b705cfSriastradh					      hint);
31803b705cfSriastradh		if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) {
31903b705cfSriastradh			if (pixmap)
32003b705cfSriastradh				screen->DestroyPixmap(pixmap);
32103b705cfSriastradh			free(privates);
32203b705cfSriastradh			free(buffer);
32303b705cfSriastradh			return NULL;
32403b705cfSriastradh		}
32503b705cfSriastradh	}
32603b705cfSriastradh
32703b705cfSriastradh	buffer->attachment = attachment;
32803b705cfSriastradh	buffer->pitch = pixmap->devKind;
32903b705cfSriastradh	buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
33003b705cfSriastradh	buffer->driverPrivate = privates;
33103b705cfSriastradh	buffer->format = format;
33203b705cfSriastradh	buffer->flags = 0;	/* not tiled */
33303b705cfSriastradh	privates->refcnt = 1;
33403b705cfSriastradh	privates->pixmap = pixmap;
33503b705cfSriastradh
33603b705cfSriastradh	if ((buffer->name = pixmap_flink(pixmap)) == 0) {
33703b705cfSriastradh		/* failed to name buffer */
33803b705cfSriastradh		screen->DestroyPixmap(pixmap);
33903b705cfSriastradh		free(privates);
34003b705cfSriastradh		free(buffer);
34103b705cfSriastradh		return NULL;
34203b705cfSriastradh	}
34303b705cfSriastradh
34403b705cfSriastradh	return buffer;
34503b705cfSriastradh}
34603b705cfSriastradh
34703b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
34803b705cfSriastradh{
34903b705cfSriastradh	if (buffer && buffer->driverPrivate) {
35003b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
35103b705cfSriastradh		if (--private->refcnt == 0) {
35203b705cfSriastradh			ScreenPtr screen = private->pixmap->drawable.pScreen;
35303b705cfSriastradh			screen->DestroyPixmap(private->pixmap);
35403b705cfSriastradh
35503b705cfSriastradh			free(private);
35603b705cfSriastradh			free(buffer);
35703b705cfSriastradh		}
35803b705cfSriastradh	} else
35903b705cfSriastradh		free(buffer);
36003b705cfSriastradh}
36103b705cfSriastradh
36203b705cfSriastradh#endif
36303b705cfSriastradh
36403b705cfSriastradhstatic void
36503b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
36603b705cfSriastradh		   DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
36703b705cfSriastradh{
36803b705cfSriastradh	I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate;
36903b705cfSriastradh	I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate;
37003b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
37103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
37203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
37303b705cfSriastradh	DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
37403b705cfSriastradh		? drawable : &srcPrivate->pixmap->drawable;
37503b705cfSriastradh	DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
37603b705cfSriastradh		? drawable : &dstPrivate->pixmap->drawable;
37703b705cfSriastradh	RegionPtr pCopyClip;
37803b705cfSriastradh	GCPtr gc;
37903b705cfSriastradh
38003b705cfSriastradh	gc = GetScratchGC(dst->depth, screen);
38103b705cfSriastradh	if (!gc)
38203b705cfSriastradh		return;
38303b705cfSriastradh
38403b705cfSriastradh	pCopyClip = REGION_CREATE(screen, NULL, 0);
38503b705cfSriastradh	REGION_COPY(screen, pCopyClip, pRegion);
38603b705cfSriastradh	(*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
38703b705cfSriastradh	ValidateGC(dst, gc);
38803b705cfSriastradh
38903b705cfSriastradh	/* Wait for the scanline to be outside the region to be copied */
39003b705cfSriastradh	if (scrn->vtSema &&
39103b705cfSriastradh	    pixmap_is_scanout(get_drawable_pixmap(dst)) &&
39203b705cfSriastradh	    intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) {
39303b705cfSriastradh		BoxPtr box;
39403b705cfSriastradh		BoxRec crtcbox;
39503b705cfSriastradh		int y1, y2;
39603b705cfSriastradh		int event, load_scan_lines_pipe;
39703b705cfSriastradh		xf86CrtcPtr crtc;
39803b705cfSriastradh		Bool full_height = FALSE;
39903b705cfSriastradh
40003b705cfSriastradh		box = REGION_EXTENTS(unused, gc->pCompositeClip);
40103b705cfSriastradh		crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox);
40203b705cfSriastradh
40303b705cfSriastradh		/*
40403b705cfSriastradh		 * Make sure the CRTC is valid and this is the real front
40503b705cfSriastradh		 * buffer
40603b705cfSriastradh		 */
40703b705cfSriastradh		if (crtc != NULL && !crtc->rotatedData) {
40803b705cfSriastradh			int pipe = intel_crtc_to_pipe(crtc);
40903b705cfSriastradh
41003b705cfSriastradh			/*
41103b705cfSriastradh			 * Make sure we don't wait for a scanline that will
41203b705cfSriastradh			 * never occur
41303b705cfSriastradh			 */
41403b705cfSriastradh			y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
41503b705cfSriastradh			y2 = (box->y2 <= crtcbox.y2) ?
41603b705cfSriastradh			    box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
41703b705cfSriastradh
41803b705cfSriastradh			if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1))
41903b705cfSriastradh			    full_height = TRUE;
42003b705cfSriastradh
42103b705cfSriastradh			/*
42203b705cfSriastradh			 * Pre-965 doesn't have SVBLANK, so we need a bit
42303b705cfSriastradh			 * of extra time for the blitter to start up and
42403b705cfSriastradh			 * do its job for a full height blit
42503b705cfSriastradh			 */
42603b705cfSriastradh			if (full_height && INTEL_INFO(intel)->gen < 040)
42703b705cfSriastradh			    y2 -= 2;
42803b705cfSriastradh
42903b705cfSriastradh			if (pipe == 0) {
43003b705cfSriastradh				event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
43103b705cfSriastradh				load_scan_lines_pipe =
43203b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
43303b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
43403b705cfSriastradh				    event = MI_WAIT_FOR_PIPEA_SVBLANK;
43503b705cfSriastradh			} else {
43603b705cfSriastradh				event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
43703b705cfSriastradh				load_scan_lines_pipe =
43803b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
43903b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
44003b705cfSriastradh				    event = MI_WAIT_FOR_PIPEB_SVBLANK;
44103b705cfSriastradh			}
44203b705cfSriastradh
44303b705cfSriastradh			if (crtc->mode.Flags & V_INTERLACE) {
44403b705cfSriastradh				/* DSL count field lines */
44503b705cfSriastradh				y1 /= 2;
44603b705cfSriastradh				y2 /= 2;
44703b705cfSriastradh			}
44803b705cfSriastradh
44903b705cfSriastradh			BEGIN_BATCH(5);
45003b705cfSriastradh			/*
45103b705cfSriastradh			 * The documentation says that the LOAD_SCAN_LINES
45203b705cfSriastradh			 * command always comes in pairs. Don't ask me why.
45303b705cfSriastradh			 */
45403b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
45503b705cfSriastradh				  load_scan_lines_pipe);
45603b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
45703b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
45803b705cfSriastradh				  load_scan_lines_pipe);
45903b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
46003b705cfSriastradh			OUT_BATCH(MI_WAIT_FOR_EVENT | event);
46103b705cfSriastradh			ADVANCE_BATCH();
46203b705cfSriastradh		}
46303b705cfSriastradh	}
46403b705cfSriastradh
46503b705cfSriastradh	/* It's important that this copy gets submitted before the
46603b705cfSriastradh	 * direct rendering client submits rendering for the next
46703b705cfSriastradh	 * frame, but we don't actually need to submit right now.  The
46803b705cfSriastradh	 * client will wait for the DRI2CopyRegion reply or the swap
46903b705cfSriastradh	 * buffer event before rendering, and we'll hit the flush
47003b705cfSriastradh	 * callback chain before those messages are sent.  We submit
47103b705cfSriastradh	 * our batch buffers from the flush callback chain so we know
47203b705cfSriastradh	 * that will happen before the client tries to render
47303b705cfSriastradh	 * again. */
47403b705cfSriastradh
47503b705cfSriastradh	gc->ops->CopyArea(src, dst, gc,
47603b705cfSriastradh			  0, 0,
47703b705cfSriastradh			  drawable->width, drawable->height,
47803b705cfSriastradh			  0, 0);
47903b705cfSriastradh
48003b705cfSriastradh	FreeScratchGC(gc);
48103b705cfSriastradh
48203b705cfSriastradh	/* And make sure the WAIT_FOR_EVENT is queued before any
48303b705cfSriastradh	 * modesetting/dpms operations on the pipe.
48403b705cfSriastradh	 */
48503b705cfSriastradh	intel_batch_submit(scrn);
48603b705cfSriastradh}
48703b705cfSriastradh
48803b705cfSriastradhstatic void
48903b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable,
49003b705cfSriastradh			 DRI2BufferPtr dst,
49103b705cfSriastradh			 DRI2BufferPtr src)
49203b705cfSriastradh{
49303b705cfSriastradh	BoxRec box;
49403b705cfSriastradh	RegionRec region;
49503b705cfSriastradh
49603b705cfSriastradh	box.x1 = 0;
49703b705cfSriastradh	box.y1 = 0;
49803b705cfSriastradh	box.x2 = drawable->width;
49903b705cfSriastradh	box.y2 = drawable->height;
50003b705cfSriastradh	REGION_INIT(pScreen, &region, &box, 0);
50103b705cfSriastradh
50203b705cfSriastradh	I830DRI2CopyRegion(drawable, &region, dst, src);
50303b705cfSriastradh}
50403b705cfSriastradh
50503b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
50603b705cfSriastradh
50703b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
50803b705cfSriastradh{
50903b705cfSriastradh	if (buffer) {
51003b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
51103b705cfSriastradh		private->refcnt++;
51203b705cfSriastradh	}
51303b705cfSriastradh}
51403b705cfSriastradh
51542542f5fSchristosstatic xf86CrtcPtr
51642542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw)
51703b705cfSriastradh{
51803b705cfSriastradh	ScreenPtr pScreen = pDraw->pScreen;
51903b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
52003b705cfSriastradh	BoxRec box, crtcbox;
52142542f5fSchristos	xf86CrtcPtr crtc = NULL;
52203b705cfSriastradh
52303b705cfSriastradh	box.x1 = pDraw->x;
52403b705cfSriastradh	box.y1 = pDraw->y;
52503b705cfSriastradh	box.x2 = box.x1 + pDraw->width;
52603b705cfSriastradh	box.y2 = box.y1 + pDraw->height;
52703b705cfSriastradh
52842542f5fSchristos	if (pDraw->type != DRAWABLE_PIXMAP)
52942542f5fSchristos		crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
53003b705cfSriastradh
53103b705cfSriastradh	/* Make sure the CRTC is valid and this is the real front buffer */
53203b705cfSriastradh	if (crtc != NULL && !crtc->rotatedData)
53342542f5fSchristos                return crtc;
53403b705cfSriastradh
53542542f5fSchristos	return NULL;
53603b705cfSriastradh}
53703b705cfSriastradh
53803b705cfSriastradhstatic RESTYPE	frame_event_client_type, frame_event_drawable_type;
53903b705cfSriastradh
54003b705cfSriastradhstruct i830_dri2_resource {
54103b705cfSriastradh	XID id;
54203b705cfSriastradh	RESTYPE type;
54303b705cfSriastradh	struct list list;
54403b705cfSriastradh};
54503b705cfSriastradh
54603b705cfSriastradhstatic struct i830_dri2_resource *
54703b705cfSriastradhget_resource(XID id, RESTYPE type)
54803b705cfSriastradh{
54903b705cfSriastradh	struct i830_dri2_resource *resource;
55003b705cfSriastradh	void *ptr;
55103b705cfSriastradh
55203b705cfSriastradh	ptr = NULL;
55303b705cfSriastradh	dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
55403b705cfSriastradh	if (ptr)
55503b705cfSriastradh		return ptr;
55603b705cfSriastradh
55703b705cfSriastradh	resource = malloc(sizeof(*resource));
55803b705cfSriastradh	if (resource == NULL)
55903b705cfSriastradh		return NULL;
56003b705cfSriastradh
56103b705cfSriastradh	if (!AddResource(id, type, resource)) {
56203b705cfSriastradh		free(resource);
56303b705cfSriastradh		return NULL;
56403b705cfSriastradh	}
56503b705cfSriastradh
56603b705cfSriastradh	resource->id = id;
56703b705cfSriastradh	resource->type = type;
56803b705cfSriastradh	list_init(&resource->list);
56903b705cfSriastradh	return resource;
57003b705cfSriastradh}
57103b705cfSriastradh
57203b705cfSriastradhstatic int
57303b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id)
57403b705cfSriastradh{
57503b705cfSriastradh	struct i830_dri2_resource *resource = data;
57603b705cfSriastradh
57703b705cfSriastradh	while (!list_is_empty(&resource->list)) {
57803b705cfSriastradh		DRI2FrameEventPtr info =
57903b705cfSriastradh			list_first_entry(&resource->list,
58003b705cfSriastradh					 DRI2FrameEventRec,
58103b705cfSriastradh					 client_resource);
58203b705cfSriastradh
58303b705cfSriastradh		list_del(&info->client_resource);
58403b705cfSriastradh		info->client = NULL;
58503b705cfSriastradh	}
58603b705cfSriastradh	free(resource);
58703b705cfSriastradh
58803b705cfSriastradh	return Success;
58903b705cfSriastradh}
59003b705cfSriastradh
59103b705cfSriastradhstatic int
59203b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id)
59303b705cfSriastradh{
59403b705cfSriastradh	struct i830_dri2_resource *resource = data;
59503b705cfSriastradh
59603b705cfSriastradh	while (!list_is_empty(&resource->list)) {
59703b705cfSriastradh		DRI2FrameEventPtr info =
59803b705cfSriastradh			list_first_entry(&resource->list,
59903b705cfSriastradh					 DRI2FrameEventRec,
60003b705cfSriastradh					 drawable_resource);
60103b705cfSriastradh
60203b705cfSriastradh		list_del(&info->drawable_resource);
60303b705cfSriastradh		info->drawable_id = None;
60403b705cfSriastradh	}
60503b705cfSriastradh	free(resource);
60603b705cfSriastradh
60703b705cfSriastradh	return Success;
60803b705cfSriastradh}
60903b705cfSriastradh
61003b705cfSriastradhstatic Bool
61103b705cfSriastradhi830_dri2_register_frame_event_resource_types(void)
61203b705cfSriastradh{
61303b705cfSriastradh	frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client");
61403b705cfSriastradh	if (!frame_event_client_type)
61503b705cfSriastradh		return FALSE;
61603b705cfSriastradh
61703b705cfSriastradh	frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable");
61803b705cfSriastradh	if (!frame_event_drawable_type)
61903b705cfSriastradh		return FALSE;
62003b705cfSriastradh
62103b705cfSriastradh	return TRUE;
62203b705cfSriastradh}
62303b705cfSriastradh
62403b705cfSriastradhstatic XID
62503b705cfSriastradhget_client_id(ClientPtr client)
62603b705cfSriastradh{
62703b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
62803b705cfSriastradh	XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key);
62903b705cfSriastradh#else
63003b705cfSriastradh	XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key);
63103b705cfSriastradh#endif
63203b705cfSriastradh	if (*ptr == 0)
63303b705cfSriastradh		*ptr = FakeClientID(client->index);
63403b705cfSriastradh	return *ptr;
63503b705cfSriastradh}
63603b705cfSriastradh
63703b705cfSriastradh/*
63803b705cfSriastradh * Hook this frame event into the server resource
63903b705cfSriastradh * database so we can clean it up if the drawable or
64003b705cfSriastradh * client exits while the swap is pending
64103b705cfSriastradh */
64203b705cfSriastradhstatic Bool
64303b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info)
64403b705cfSriastradh{
64503b705cfSriastradh	struct i830_dri2_resource *resource;
64603b705cfSriastradh
64703b705cfSriastradh	resource = get_resource(get_client_id(info->client),
64803b705cfSriastradh				frame_event_client_type);
64903b705cfSriastradh	if (resource == NULL)
65003b705cfSriastradh		return FALSE;
65103b705cfSriastradh
65203b705cfSriastradh	list_add(&info->client_resource, &resource->list);
65303b705cfSriastradh
65403b705cfSriastradh	resource = get_resource(info->drawable_id, frame_event_drawable_type);
65503b705cfSriastradh	if (resource == NULL) {
65603b705cfSriastradh		list_del(&info->client_resource);
65703b705cfSriastradh		return FALSE;
65803b705cfSriastradh	}
65903b705cfSriastradh
66003b705cfSriastradh	list_add(&info->drawable_resource, &resource->list);
66103b705cfSriastradh
66203b705cfSriastradh	return TRUE;
66303b705cfSriastradh}
66403b705cfSriastradh
66503b705cfSriastradhstatic void
66642542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info)
66703b705cfSriastradh{
66803b705cfSriastradh	list_del(&info->client_resource);
66903b705cfSriastradh	list_del(&info->drawable_resource);
67003b705cfSriastradh
67103b705cfSriastradh	if (info->front)
67242542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->front);
67303b705cfSriastradh	if (info->back)
67442542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->back);
67503b705cfSriastradh
67603b705cfSriastradh	free(info);
67703b705cfSriastradh}
67803b705cfSriastradh
67913496ba1Ssnjstatic struct intel_uxa_pixmap *
68003b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back)
68103b705cfSriastradh{
68213496ba1Ssnj	struct intel_uxa_pixmap *new_front = NULL, *new_back;
68303b705cfSriastradh	RegionRec region;
68403b705cfSriastradh
68503b705cfSriastradh	/* Post damage on the front buffer so that listeners, such
68603b705cfSriastradh	 * as DisplayLink know take a copy and shove it over the USB.
68703b705cfSriastradh	 * also for sw cursors.
68803b705cfSriastradh	 */
68903b705cfSriastradh	region.extents.x1 = region.extents.y1 = 0;
69003b705cfSriastradh	region.extents.x2 = front->drawable.width;
69103b705cfSriastradh	region.extents.y2 = front->drawable.height;
69203b705cfSriastradh	region.data = NULL;
69303b705cfSriastradh	DamageRegionAppend(&front->drawable, &region);
69403b705cfSriastradh
69513496ba1Ssnj	new_front = intel_uxa_get_pixmap_private(back);
69613496ba1Ssnj	new_back = intel_uxa_get_pixmap_private(front);
69713496ba1Ssnj	intel_uxa_set_pixmap_private(front, new_front);
69813496ba1Ssnj	intel_uxa_set_pixmap_private(back, new_back);
69903b705cfSriastradh	new_front->busy = 1;
70003b705cfSriastradh	new_back->busy = -1;
70103b705cfSriastradh
70203b705cfSriastradh	DamageRegionProcessPending(&front->drawable);
70303b705cfSriastradh
70403b705cfSriastradh	return new_front;
70503b705cfSriastradh}
70603b705cfSriastradh
70703b705cfSriastradhstatic void
70803b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
70903b705cfSriastradh{
71003b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv, back_priv;
71103b705cfSriastradh	int tmp;
71213496ba1Ssnj	struct intel_uxa_pixmap *new_front;
71303b705cfSriastradh
71403b705cfSriastradh	front_priv = front->driverPrivate;
71503b705cfSriastradh	back_priv = back->driverPrivate;
71603b705cfSriastradh
71703b705cfSriastradh	/* Swap BO names so DRI works */
71803b705cfSriastradh	tmp = front->name;
71903b705cfSriastradh	front->name = back->name;
72003b705cfSriastradh	back->name = tmp;
72103b705cfSriastradh
72203b705cfSriastradh	/* Swap pixmap bos */
72303b705cfSriastradh	new_front = intel_exchange_pixmap_buffers(intel,
72403b705cfSriastradh						  front_priv->pixmap,
72503b705cfSriastradh						  back_priv->pixmap);
72603b705cfSriastradh	dri_bo_unreference (intel->front_buffer);
72703b705cfSriastradh	intel->front_buffer = new_front->bo;
72803b705cfSriastradh	dri_bo_reference (intel->front_buffer);
72903b705cfSriastradh}
73003b705cfSriastradh
73103b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
73203b705cfSriastradh{
73303b705cfSriastradh	drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
73403b705cfSriastradh	assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
73503b705cfSriastradh	return bo;
73603b705cfSriastradh}
73703b705cfSriastradh
73842542f5fSchristosstatic void
73942542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
74042542f5fSchristos{
74142542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
74242542f5fSchristos
74342542f5fSchristos        I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
74442542f5fSchristos                                 usec % 1000000,
74542542f5fSchristos                                 info);
74642542f5fSchristos}
74742542f5fSchristos
74842542f5fSchristosstatic void
74942542f5fSchristosI830DRI2FlipAbort(void *pageflip_data)
75042542f5fSchristos{
75142542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
75242542f5fSchristos
75342542f5fSchristos        i830_dri2_del_frame_event(info);
75442542f5fSchristos}
75542542f5fSchristos
75603b705cfSriastradh/*
75703b705cfSriastradh * Our internal swap routine takes care of actually exchanging, blitting, or
75803b705cfSriastradh * flipping buffers as necessary.
75903b705cfSriastradh */
76003b705cfSriastradhstatic Bool
76103b705cfSriastradhI830DRI2ScheduleFlip(struct intel_screen_private *intel,
76203b705cfSriastradh		     DrawablePtr draw,
76303b705cfSriastradh		     DRI2FrameEventPtr info)
76403b705cfSriastradh{
76503b705cfSriastradh	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
76603b705cfSriastradh	drm_intel_bo *new_back, *old_back;
76703b705cfSriastradh	int tmp_name;
76803b705cfSriastradh
76903b705cfSriastradh	if (!intel->use_triple_buffer) {
77003b705cfSriastradh		info->type = DRI2_SWAP;
77103b705cfSriastradh		if (!intel_do_pageflip(intel,
77203b705cfSriastradh				       get_pixmap_bo(priv),
77342542f5fSchristos				       info->pipe, FALSE, info,
77442542f5fSchristos                                       I830DRI2FlipComplete,
77542542f5fSchristos                                       I830DRI2FlipAbort))
77603b705cfSriastradh			return FALSE;
77703b705cfSriastradh
77803b705cfSriastradh		I830DRI2ExchangeBuffers(intel, info->front, info->back);
77903b705cfSriastradh		return TRUE;
78003b705cfSriastradh	}
78103b705cfSriastradh
78203b705cfSriastradh	if (intel->pending_flip[info->pipe]) {
78303b705cfSriastradh		assert(intel->pending_flip[info->pipe]->chain == NULL);
78403b705cfSriastradh		intel->pending_flip[info->pipe]->chain = info;
78503b705cfSriastradh		return TRUE;
78603b705cfSriastradh	}
78703b705cfSriastradh
78803b705cfSriastradh	if (intel->back_buffer == NULL) {
78903b705cfSriastradh		new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
79003b705cfSriastradh					      intel->front_buffer->size, 0);
79103b705cfSriastradh		if (new_back == NULL)
79203b705cfSriastradh			return FALSE;
79303b705cfSriastradh
79403b705cfSriastradh		if (intel->front_tiling != I915_TILING_NONE) {
79503b705cfSriastradh			uint32_t tiling = intel->front_tiling;
79603b705cfSriastradh			drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
79703b705cfSriastradh			if (tiling != intel->front_tiling) {
79803b705cfSriastradh				drm_intel_bo_unreference(new_back);
79903b705cfSriastradh				return FALSE;
80003b705cfSriastradh			}
80103b705cfSriastradh		}
80203b705cfSriastradh
80303b705cfSriastradh		drm_intel_bo_disable_reuse(new_back);
80403b705cfSriastradh		dri_bo_flink(new_back, &intel->back_name);
80503b705cfSriastradh	} else {
80603b705cfSriastradh		new_back = intel->back_buffer;
80703b705cfSriastradh		intel->back_buffer = NULL;
80803b705cfSriastradh	}
80903b705cfSriastradh
81003b705cfSriastradh	old_back = get_pixmap_bo(priv);
81142542f5fSchristos	if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
81203b705cfSriastradh		intel->back_buffer = new_back;
81303b705cfSriastradh		return FALSE;
81403b705cfSriastradh	}
81503b705cfSriastradh	info->type = DRI2_SWAP_CHAIN;
81603b705cfSriastradh	intel->pending_flip[info->pipe] = info;
81703b705cfSriastradh
81803b705cfSriastradh	priv = info->front->driverPrivate;
81903b705cfSriastradh
82003b705cfSriastradh	/* Exchange the current front-buffer with the fresh bo */
82103b705cfSriastradh
82203b705cfSriastradh	intel->back_buffer = intel->front_buffer;
82303b705cfSriastradh	drm_intel_bo_reference(intel->back_buffer);
82413496ba1Ssnj	intel_set_pixmap_bo(priv->pixmap, new_back);
82513496ba1Ssnj	drm_intel_bo_unreference(new_back);
82603b705cfSriastradh
82703b705cfSriastradh	tmp_name = info->front->name;
82803b705cfSriastradh	info->front->name = intel->back_name;
82903b705cfSriastradh	intel->back_name = tmp_name;
83003b705cfSriastradh
83103b705cfSriastradh	/* Then flip DRI2 pointers and update the screen pixmap */
83203b705cfSriastradh	I830DRI2ExchangeBuffers(intel, info->front, info->back);
83303b705cfSriastradh	DRI2SwapComplete(info->client, draw, 0, 0, 0,
83403b705cfSriastradh			 DRI2_EXCHANGE_COMPLETE,
83503b705cfSriastradh			 info->event_complete,
83603b705cfSriastradh			 info->event_data);
83703b705cfSriastradh	return TRUE;
83803b705cfSriastradh}
83903b705cfSriastradh
84003b705cfSriastradhstatic Bool
84103b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
84203b705cfSriastradh{
84303b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen);
84403b705cfSriastradh	struct intel_screen_private *intel = intel_get_screen_private(pScrn);
84503b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
84603b705cfSriastradh	I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
84703b705cfSriastradh	PixmapPtr front_pixmap = front_priv->pixmap;
84803b705cfSriastradh	PixmapPtr back_pixmap = back_priv->pixmap;
84913496ba1Ssnj	struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap);
85013496ba1Ssnj	struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap);
85103b705cfSriastradh
85203b705cfSriastradh	if (!pScrn->vtSema)
85303b705cfSriastradh		return FALSE;
85403b705cfSriastradh
85542542f5fSchristos	if (I830DRI2DrawableCrtc(drawable) == NULL)
85603b705cfSriastradh		return FALSE;
85703b705cfSriastradh
85803b705cfSriastradh	if (!DRI2CanFlip(drawable))
85903b705cfSriastradh		return FALSE;
86003b705cfSriastradh
86103b705cfSriastradh	if (intel->shadow_present)
86203b705cfSriastradh		return FALSE;
86303b705cfSriastradh
86403b705cfSriastradh	if (!intel->use_pageflipping)
86503b705cfSriastradh		return FALSE;
86603b705cfSriastradh
86703b705cfSriastradh	if (front_pixmap->drawable.width != back_pixmap->drawable.width)
86803b705cfSriastradh		return FALSE;
86903b705cfSriastradh
87003b705cfSriastradh	if (front_pixmap->drawable.height != back_pixmap->drawable.height)
87103b705cfSriastradh		return FALSE;
87203b705cfSriastradh
87303b705cfSriastradh	/* XXX should we be checking depth instead of bpp? */
87403b705cfSriastradh#if 0
87503b705cfSriastradh	if (front_pixmap->drawable.depth != back_pixmap->drawable.depth)
87603b705cfSriastradh		return FALSE;
87703b705cfSriastradh#else
87803b705cfSriastradh	if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
87903b705cfSriastradh		return FALSE;
88003b705cfSriastradh#endif
88103b705cfSriastradh
88203b705cfSriastradh	/* prevent an implicit tiling mode change */
88303b705cfSriastradh	if (front_intel->tiling != back_intel->tiling)
88403b705cfSriastradh		return FALSE;
88503b705cfSriastradh
88642542f5fSchristos	if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2))
88742542f5fSchristos		return FALSE;
88842542f5fSchristos
88903b705cfSriastradh	return TRUE;
89003b705cfSriastradh}
89103b705cfSriastradh
89203b705cfSriastradhvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
89303b705cfSriastradh			       unsigned int tv_usec, DRI2FrameEventPtr swap_info)
89403b705cfSriastradh{
89503b705cfSriastradh	intel_screen_private *intel = swap_info->intel;
89603b705cfSriastradh	DrawablePtr drawable;
89703b705cfSriastradh	int status;
89803b705cfSriastradh
89903b705cfSriastradh	if (!swap_info->drawable_id)
90003b705cfSriastradh		status = BadDrawable;
90103b705cfSriastradh	else
90203b705cfSriastradh		status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
90303b705cfSriastradh					   M_ANY, DixWriteAccess);
90403b705cfSriastradh	if (status != Success) {
90542542f5fSchristos		i830_dri2_del_frame_event(swap_info);
90603b705cfSriastradh		return;
90703b705cfSriastradh	}
90803b705cfSriastradh
90903b705cfSriastradh
91003b705cfSriastradh	switch (swap_info->type) {
91103b705cfSriastradh	case DRI2_FLIP:
91203b705cfSriastradh		/* If we can still flip... */
91303b705cfSriastradh		if (can_exchange(drawable, swap_info->front, swap_info->back) &&
91403b705cfSriastradh		    I830DRI2ScheduleFlip(intel, drawable, swap_info))
91503b705cfSriastradh			return;
91603b705cfSriastradh
91703b705cfSriastradh		/* else fall through to exchange/blit */
91803b705cfSriastradh	case DRI2_SWAP: {
91903b705cfSriastradh		I830DRI2FallbackBlitSwap(drawable,
92003b705cfSriastradh					 swap_info->front, swap_info->back);
92103b705cfSriastradh		DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
92203b705cfSriastradh				 DRI2_BLIT_COMPLETE,
92303b705cfSriastradh				 swap_info->client ? swap_info->event_complete : NULL,
92403b705cfSriastradh				 swap_info->event_data);
92503b705cfSriastradh		break;
92603b705cfSriastradh	}
92703b705cfSriastradh	case DRI2_WAITMSC:
92803b705cfSriastradh		if (swap_info->client)
92903b705cfSriastradh			DRI2WaitMSCComplete(swap_info->client, drawable,
93003b705cfSriastradh					    frame, tv_sec, tv_usec);
93103b705cfSriastradh		break;
93203b705cfSriastradh	default:
93303b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
93403b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
93503b705cfSriastradh		/* Unknown type */
93603b705cfSriastradh		break;
93703b705cfSriastradh	}
93803b705cfSriastradh
93942542f5fSchristos	i830_dri2_del_frame_event(swap_info);
94003b705cfSriastradh}
94103b705cfSriastradh
94203b705cfSriastradhvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
94303b705cfSriastradh			      unsigned int tv_usec, DRI2FrameEventPtr flip_info)
94403b705cfSriastradh{
94503b705cfSriastradh	struct intel_screen_private *intel = flip_info->intel;
94603b705cfSriastradh	DrawablePtr drawable;
94703b705cfSriastradh	DRI2FrameEventPtr chain;
94803b705cfSriastradh
94903b705cfSriastradh	drawable = NULL;
95003b705cfSriastradh	if (flip_info->drawable_id)
95103b705cfSriastradh		dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
95203b705cfSriastradh				  M_ANY, DixWriteAccess);
95303b705cfSriastradh
95403b705cfSriastradh
95503b705cfSriastradh	/* We assume our flips arrive in order, so we don't check the frame */
95603b705cfSriastradh	switch (flip_info->type) {
95703b705cfSriastradh	case DRI2_SWAP:
95803b705cfSriastradh		if (!drawable)
95903b705cfSriastradh			break;
96003b705cfSriastradh
96103b705cfSriastradh		/* Check for too small vblank count of pageflip completion, taking wraparound
96203b705cfSriastradh		 * into account. This usually means some defective kms pageflip completion,
96303b705cfSriastradh		 * causing wrong (msc, ust) return values and possible visual corruption.
96403b705cfSriastradh		 */
96503b705cfSriastradh		if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
96603b705cfSriastradh			static int limit = 5;
96703b705cfSriastradh
96803b705cfSriastradh			/* XXX we are currently hitting this path with older
96903b705cfSriastradh			 * kernels, so make it quieter.
97003b705cfSriastradh			 */
97103b705cfSriastradh			if (limit) {
97203b705cfSriastradh				xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
97303b705cfSriastradh					   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
97403b705cfSriastradh					   __func__, frame, flip_info->frame);
97503b705cfSriastradh				limit--;
97603b705cfSriastradh			}
97703b705cfSriastradh
97803b705cfSriastradh			/* All-0 values signal timestamping failure. */
97903b705cfSriastradh			frame = tv_sec = tv_usec = 0;
98003b705cfSriastradh		}
98103b705cfSriastradh
98203b705cfSriastradh		DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
98303b705cfSriastradh				 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
98403b705cfSriastradh				 flip_info->event_data);
98503b705cfSriastradh		break;
98603b705cfSriastradh
98703b705cfSriastradh	case DRI2_SWAP_CHAIN:
98803b705cfSriastradh		assert(intel->pending_flip[flip_info->pipe] == flip_info);
98903b705cfSriastradh		intel->pending_flip[flip_info->pipe] = NULL;
99003b705cfSriastradh
99103b705cfSriastradh		chain = flip_info->chain;
99203b705cfSriastradh		if (chain) {
99303b705cfSriastradh			DrawablePtr chain_drawable = NULL;
99403b705cfSriastradh			if (chain->drawable_id)
99503b705cfSriastradh				 dixLookupDrawable(&chain_drawable,
99603b705cfSriastradh						   chain->drawable_id,
99703b705cfSriastradh						   serverClient,
99803b705cfSriastradh						   M_ANY, DixWriteAccess);
99903b705cfSriastradh			if (chain_drawable == NULL) {
100042542f5fSchristos				i830_dri2_del_frame_event(chain);
100103b705cfSriastradh			} else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
100203b705cfSriastradh				   !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
100303b705cfSriastradh				I830DRI2FallbackBlitSwap(chain_drawable,
100403b705cfSriastradh							 chain->front,
100503b705cfSriastradh							 chain->back);
100603b705cfSriastradh
100703b705cfSriastradh				DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
100803b705cfSriastradh						 DRI2_BLIT_COMPLETE,
100903b705cfSriastradh						 chain->client ? chain->event_complete : NULL,
101003b705cfSriastradh						 chain->event_data);
101142542f5fSchristos				i830_dri2_del_frame_event(chain);
101203b705cfSriastradh			}
101303b705cfSriastradh		}
101403b705cfSriastradh		break;
101503b705cfSriastradh
101603b705cfSriastradh	default:
101703b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
101803b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
101903b705cfSriastradh		/* Unknown type */
102003b705cfSriastradh		break;
102103b705cfSriastradh	}
102203b705cfSriastradh
102342542f5fSchristos	i830_dri2_del_frame_event(flip_info);
102403b705cfSriastradh}
102503b705cfSriastradh
102603b705cfSriastradhstatic uint32_t pipe_select(int pipe)
102703b705cfSriastradh{
102803b705cfSriastradh	if (pipe > 1)
102903b705cfSriastradh		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
103003b705cfSriastradh	else if (pipe > 0)
103103b705cfSriastradh		return DRM_VBLANK_SECONDARY;
103203b705cfSriastradh	else
103303b705cfSriastradh		return 0;
103403b705cfSriastradh}
103503b705cfSriastradh
103642542f5fSchristosstatic void
103742542f5fSchristosintel_dri2_vblank_handler(ScrnInfoPtr scrn,
103842542f5fSchristos                          xf86CrtcPtr crtc,
103942542f5fSchristos                          uint64_t msc,
104042542f5fSchristos                          uint64_t usec,
104142542f5fSchristos                          void *data)
104242542f5fSchristos{
104342542f5fSchristos        DRI2FrameEventPtr swap_info = data;
104442542f5fSchristos
104542542f5fSchristos        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
104642542f5fSchristos}
104742542f5fSchristos
104842542f5fSchristosstatic void
104942542f5fSchristosintel_dri2_vblank_abort(ScrnInfoPtr scrn,
105042542f5fSchristos                        xf86CrtcPtr crtc,
105142542f5fSchristos                        void *data)
105242542f5fSchristos{
105342542f5fSchristos        DRI2FrameEventPtr swap_info = data;
105442542f5fSchristos
105542542f5fSchristos        i830_dri2_del_frame_event(swap_info);
105642542f5fSchristos}
105742542f5fSchristos
105803b705cfSriastradh/*
105903b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the
106003b705cfSriastradh * appropriate frame.
106103b705cfSriastradh *
106203b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
106303b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap
106403b705cfSriastradh * interval for the drawable.
106503b705cfSriastradh *
106603b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap
106703b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame
106803b705cfSriastradh * immediately following the received event.
106903b705cfSriastradh *
107003b705cfSriastradh * The client will be blocked if it tries to perform further GL commands
107103b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the
107203b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if
107303b705cfSriastradh * they access buffers busy with the flip.
107403b705cfSriastradh *
107503b705cfSriastradh * When the swap is complete, the driver should call into the server so it
107603b705cfSriastradh * can send any swap complete events that have been requested.
107703b705cfSriastradh */
107803b705cfSriastradhstatic int
107903b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
108003b705cfSriastradh		     DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
108103b705cfSriastradh		     CARD64 remainder, DRI2SwapEventPtr func, void *data)
108203b705cfSriastradh{
108303b705cfSriastradh	ScreenPtr screen = draw->pScreen;
108403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
108503b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
108603b705cfSriastradh	drmVBlank vbl;
108742542f5fSchristos	int ret;
108842542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
108942542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
109042542f5fSchristos        int flip = 0;
109103b705cfSriastradh	DRI2FrameEventPtr swap_info = NULL;
109203b705cfSriastradh	enum DRI2FrameEventType swap_type = DRI2_SWAP;
109342542f5fSchristos	uint64_t current_msc, current_ust;
109442542f5fSchristos        uint64_t request_msc;
109542542f5fSchristos        uint32_t seq;
109603b705cfSriastradh
109703b705cfSriastradh	/* Drawable not displayed... just complete the swap */
109803b705cfSriastradh	if (pipe == -1)
109903b705cfSriastradh	    goto blit_fallback;
110003b705cfSriastradh
110103b705cfSriastradh	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
110203b705cfSriastradh	if (!swap_info)
110303b705cfSriastradh	    goto blit_fallback;
110403b705cfSriastradh
110503b705cfSriastradh	swap_info->intel = intel;
110603b705cfSriastradh	swap_info->drawable_id = draw->id;
110703b705cfSriastradh	swap_info->client = client;
110803b705cfSriastradh	swap_info->event_complete = func;
110903b705cfSriastradh	swap_info->event_data = data;
111003b705cfSriastradh	swap_info->front = front;
111103b705cfSriastradh	swap_info->back = back;
111203b705cfSriastradh	swap_info->pipe = pipe;
111303b705cfSriastradh
111403b705cfSriastradh	if (!i830_dri2_add_frame_event(swap_info)) {
111503b705cfSriastradh	    free(swap_info);
111603b705cfSriastradh	    swap_info = NULL;
111703b705cfSriastradh	    goto blit_fallback;
111803b705cfSriastradh	}
111903b705cfSriastradh
112003b705cfSriastradh	I830DRI2ReferenceBuffer(front);
112103b705cfSriastradh	I830DRI2ReferenceBuffer(back);
112203b705cfSriastradh
112342542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
112442542f5fSchristos	if (ret)
112542542f5fSchristos	    goto blit_fallback;
112603b705cfSriastradh
112703b705cfSriastradh	/* Flips need to be submitted one frame before */
112803b705cfSriastradh	if (can_exchange(draw, front, back)) {
112903b705cfSriastradh	    swap_type = DRI2_FLIP;
113003b705cfSriastradh	    flip = 1;
113103b705cfSriastradh	}
113203b705cfSriastradh
113303b705cfSriastradh	swap_info->type = swap_type;
113403b705cfSriastradh
113503b705cfSriastradh	/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
113603b705cfSriastradh	 * Do it early, so handling of different timing constraints
113703b705cfSriastradh	 * for divisor, remainder and msc vs. target_msc works.
113803b705cfSriastradh	 */
113903b705cfSriastradh	if (*target_msc > 0)
114003b705cfSriastradh		*target_msc -= flip;
114103b705cfSriastradh
114203b705cfSriastradh	/*
114303b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc
114403b705cfSriastradh	 * we just need to make sure target_msc passes before initiating
114503b705cfSriastradh	 * the swap.
114603b705cfSriastradh	 */
114703b705cfSriastradh	if (divisor == 0 || current_msc < *target_msc) {
114803b705cfSriastradh		/*
114903b705cfSriastradh		 * If we can, schedule the flip directly from here rather
115003b705cfSriastradh		 * than waiting for an event from the kernel for the current
115103b705cfSriastradh		 * (or a past) MSC.
115203b705cfSriastradh		 */
115303b705cfSriastradh		if (flip && divisor == 0 && current_msc >= *target_msc &&
115403b705cfSriastradh		    I830DRI2ScheduleFlip(intel, draw, swap_info))
115503b705cfSriastradh			return TRUE;
115603b705cfSriastradh
115703b705cfSriastradh		vbl.request.type =
115803b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
115903b705cfSriastradh
116003b705cfSriastradh		/* If non-pageflipping, but blitting/exchanging, we need to use
116103b705cfSriastradh		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
116203b705cfSriastradh		 * on.
116303b705cfSriastradh		 */
116403b705cfSriastradh		if (flip == 0)
116503b705cfSriastradh			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
116603b705cfSriastradh
116703b705cfSriastradh		/* If target_msc already reached or passed, set it to
116803b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
116903b705cfSriastradh		 * to the caller. This makes swap_interval logic more robust.
117003b705cfSriastradh		 */
117103b705cfSriastradh		if (current_msc >= *target_msc)
117203b705cfSriastradh			*target_msc = current_msc;
117303b705cfSriastradh
117442542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
117542542f5fSchristos                if (!seq)
117642542f5fSchristos                        goto blit_fallback;
117742542f5fSchristos
117842542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
117942542f5fSchristos		vbl.request.signal = seq;
118042542f5fSchristos
118103b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
118203b705cfSriastradh		if (ret) {
118303b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
118403b705cfSriastradh				   "divisor 0 get vblank counter failed: %s\n",
118503b705cfSriastradh				   strerror(errno));
118603b705cfSriastradh			goto blit_fallback;
118703b705cfSriastradh		}
118803b705cfSriastradh
118942542f5fSchristos                *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
119003b705cfSriastradh		swap_info->frame = *target_msc;
119103b705cfSriastradh
119203b705cfSriastradh		return TRUE;
119303b705cfSriastradh	}
119403b705cfSriastradh
119503b705cfSriastradh	/*
119603b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
119703b705cfSriastradh	 * and we need to queue an event that will satisfy the divisor/remainder
119803b705cfSriastradh	 * equation.
119903b705cfSriastradh	 */
120003b705cfSriastradh	vbl.request.type =
120103b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
120203b705cfSriastradh	if (flip == 0)
120303b705cfSriastradh		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
120403b705cfSriastradh
120542542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
120642542f5fSchristos                remainder;
120703b705cfSriastradh
120803b705cfSriastradh	/*
120903b705cfSriastradh	 * If the calculated deadline vbl.request.sequence is smaller than
121003b705cfSriastradh	 * or equal to current_msc, it means we've passed the last point
121103b705cfSriastradh	 * when effective onset frame seq could satisfy
121203b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
121303b705cfSriastradh	 * this will happen.
121403b705cfSriastradh
121503b705cfSriastradh	 * This comparison takes the 1 frame swap delay in pageflipping mode
121603b705cfSriastradh	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
121703b705cfSriastradh	 * if we are blitting/exchanging instead of flipping.
121803b705cfSriastradh	 */
121942542f5fSchristos	if (request_msc <= current_msc)
122042542f5fSchristos		request_msc += divisor;
122142542f5fSchristos
122242542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
122342542f5fSchristos        if (!seq)
122442542f5fSchristos                goto blit_fallback;
122503b705cfSriastradh
122603b705cfSriastradh	/* Account for 1 frame extra pageflip delay if flip > 0 */
122742542f5fSchristos        vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
122842542f5fSchristos	vbl.request.signal = seq;
122903b705cfSriastradh
123003b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
123103b705cfSriastradh	if (ret) {
123203b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
123303b705cfSriastradh			   "final get vblank counter failed: %s\n",
123403b705cfSriastradh			   strerror(errno));
123503b705cfSriastradh		goto blit_fallback;
123603b705cfSriastradh	}
123703b705cfSriastradh
123803b705cfSriastradh	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
123942542f5fSchristos	*target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
124003b705cfSriastradh	swap_info->frame = *target_msc;
124103b705cfSriastradh
124203b705cfSriastradh	return TRUE;
124303b705cfSriastradh
124403b705cfSriastradhblit_fallback:
124503b705cfSriastradh	I830DRI2FallbackBlitSwap(draw, front, back);
124603b705cfSriastradh	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
124703b705cfSriastradh	if (swap_info)
124842542f5fSchristos	    i830_dri2_del_frame_event(swap_info);
124903b705cfSriastradh	*target_msc = 0; /* offscreen, so zero out target vblank count */
125003b705cfSriastradh	return TRUE;
125103b705cfSriastradh}
125203b705cfSriastradh
125303b705cfSriastradhstatic uint64_t gettime_us(void)
125403b705cfSriastradh{
125503b705cfSriastradh	struct timespec tv;
125603b705cfSriastradh
125703b705cfSriastradh	if (clock_gettime(CLOCK_MONOTONIC, &tv))
125803b705cfSriastradh		return 0;
125903b705cfSriastradh
126003b705cfSriastradh	return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
126103b705cfSriastradh}
126203b705cfSriastradh
126303b705cfSriastradh/*
126403b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's
126503b705cfSriastradh * crtc.
126603b705cfSriastradh */
126703b705cfSriastradhstatic int
126803b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
126903b705cfSriastradh{
127003b705cfSriastradh	ScreenPtr screen = draw->pScreen;
127103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
127242542f5fSchristos	int ret;
127342542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
127403b705cfSriastradh
127503b705cfSriastradh	/* Drawable not displayed, make up a *monotonic* value */
127642542f5fSchristos	if (crtc == NULL) {
127742542f5fSchristosfail:
127803b705cfSriastradh		*ust = gettime_us();
127903b705cfSriastradh		*msc = 0;
128003b705cfSriastradh		return TRUE;
128103b705cfSriastradh	}
128203b705cfSriastradh
128342542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
128403b705cfSriastradh	if (ret) {
128503b705cfSriastradh		static int limit = 5;
128603b705cfSriastradh		if (limit) {
128703b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
128803b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
128903b705cfSriastradh				   __FUNCTION__, __LINE__,
129003b705cfSriastradh				   strerror(errno));
129103b705cfSriastradh			limit--;
129203b705cfSriastradh		}
129342542f5fSchristos		goto fail;
129403b705cfSriastradh	}
129503b705cfSriastradh
129603b705cfSriastradh	return TRUE;
129703b705cfSriastradh}
129803b705cfSriastradh
129903b705cfSriastradh/*
130003b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied.
130103b705cfSriastradh *
130203b705cfSriastradh * We need to handle the event and ask the server to wake up the client when
130303b705cfSriastradh * we receive it.
130403b705cfSriastradh */
130503b705cfSriastradhstatic int
130603b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
130703b705cfSriastradh			CARD64 divisor, CARD64 remainder)
130803b705cfSriastradh{
130903b705cfSriastradh	ScreenPtr screen = draw->pScreen;
131003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
131103b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
131203b705cfSriastradh	DRI2FrameEventPtr wait_info;
131303b705cfSriastradh	drmVBlank vbl;
131442542f5fSchristos	int ret;
131542542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
131642542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
131742542f5fSchristos	CARD64 current_msc, current_ust, request_msc;
131842542f5fSchristos        uint32_t seq;
131903b705cfSriastradh
132003b705cfSriastradh	/* Drawable not visible, return immediately */
132103b705cfSriastradh	if (pipe == -1)
132203b705cfSriastradh		goto out_complete;
132303b705cfSriastradh
132403b705cfSriastradh	wait_info = calloc(1, sizeof(DRI2FrameEventRec));
132503b705cfSriastradh	if (!wait_info)
132603b705cfSriastradh		goto out_complete;
132703b705cfSriastradh
132803b705cfSriastradh	wait_info->intel = intel;
132903b705cfSriastradh	wait_info->drawable_id = draw->id;
133003b705cfSriastradh	wait_info->client = client;
133103b705cfSriastradh	wait_info->type = DRI2_WAITMSC;
133203b705cfSriastradh
133303b705cfSriastradh	if (!i830_dri2_add_frame_event(wait_info)) {
133403b705cfSriastradh	    free(wait_info);
133503b705cfSriastradh	    wait_info = NULL;
133603b705cfSriastradh	    goto out_complete;
133703b705cfSriastradh	}
133803b705cfSriastradh
133903b705cfSriastradh	/* Get current count */
134042542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
134142542f5fSchristos	if (ret)
134242542f5fSchristos	    goto out_free;
134303b705cfSriastradh
134403b705cfSriastradh	/*
134503b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc,
134603b705cfSriastradh	 * we just need to make sure target_msc passes  before waking up the
134703b705cfSriastradh	 * client.
134803b705cfSriastradh	 */
134903b705cfSriastradh	if (divisor == 0 || current_msc < target_msc) {
135003b705cfSriastradh		/* If target_msc already reached or passed, set it to
135103b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
135203b705cfSriastradh		 * to the caller. This keeps the client from continually
135303b705cfSriastradh		 * sending us MSC targets from the past by forcibly updating
135403b705cfSriastradh		 * their count on this call.
135503b705cfSriastradh		 */
135642542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
135742542f5fSchristos                if (!seq)
135842542f5fSchristos                        goto out_free;
135942542f5fSchristos
136003b705cfSriastradh		if (current_msc >= target_msc)
136103b705cfSriastradh			target_msc = current_msc;
136203b705cfSriastradh		vbl.request.type =
136303b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
136442542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
136542542f5fSchristos		vbl.request.signal = seq;
136642542f5fSchristos
136703b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
136803b705cfSriastradh		if (ret) {
136903b705cfSriastradh			static int limit = 5;
137003b705cfSriastradh			if (limit) {
137103b705cfSriastradh				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
137203b705cfSriastradh					   "%s:%d get vblank counter failed: %s\n",
137303b705cfSriastradh					   __FUNCTION__, __LINE__,
137403b705cfSriastradh					   strerror(errno));
137503b705cfSriastradh				limit--;
137603b705cfSriastradh			}
137703b705cfSriastradh			goto out_free;
137803b705cfSriastradh		}
137903b705cfSriastradh
138042542f5fSchristos		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
138103b705cfSriastradh		DRI2BlockClient(client, draw);
138203b705cfSriastradh		return TRUE;
138303b705cfSriastradh	}
138403b705cfSriastradh
138503b705cfSriastradh	/*
138603b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
138703b705cfSriastradh	 * so we queue an event that will satisfy the divisor/remainder equation.
138803b705cfSriastradh	 */
138903b705cfSriastradh	vbl.request.type =
139003b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
139103b705cfSriastradh
139242542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
139342542f5fSchristos                remainder;
139403b705cfSriastradh	/*
139503b705cfSriastradh	 * If calculated remainder is larger than requested remainder,
139603b705cfSriastradh	 * it means we've passed the last point where
139703b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
139803b705cfSriastradh	 * that will happen.
139903b705cfSriastradh	 */
140003b705cfSriastradh	if ((current_msc % divisor) >= remainder)
140142542f5fSchristos                request_msc += divisor;
140242542f5fSchristos
140342542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
140442542f5fSchristos        if (!seq)
140542542f5fSchristos                goto out_free;
140642542f5fSchristos
140742542f5fSchristos	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
140842542f5fSchristos	vbl.request.signal = seq;
140903b705cfSriastradh
141003b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
141103b705cfSriastradh	if (ret) {
141203b705cfSriastradh		static int limit = 5;
141303b705cfSriastradh		if (limit) {
141403b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
141503b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
141603b705cfSriastradh				   __FUNCTION__, __LINE__,
141703b705cfSriastradh				   strerror(errno));
141803b705cfSriastradh			limit--;
141903b705cfSriastradh		}
142003b705cfSriastradh		goto out_free;
142103b705cfSriastradh	}
142203b705cfSriastradh
142342542f5fSchristos	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
142403b705cfSriastradh	DRI2BlockClient(client, draw);
142503b705cfSriastradh
142603b705cfSriastradh	return TRUE;
142703b705cfSriastradh
142803b705cfSriastradhout_free:
142942542f5fSchristos	i830_dri2_del_frame_event(wait_info);
143003b705cfSriastradhout_complete:
143103b705cfSriastradh	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
143203b705cfSriastradh	return TRUE;
143303b705cfSriastradh}
143403b705cfSriastradh
143503b705cfSriastradhstatic int dri2_server_generation;
143603b705cfSriastradh#endif
143703b705cfSriastradh
143803b705cfSriastradhstatic int has_i830_dri(void)
143903b705cfSriastradh{
144003b705cfSriastradh	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
144103b705cfSriastradh}
144203b705cfSriastradh
144303b705cfSriastradhstatic const char *dri_driver_name(intel_screen_private *intel)
144403b705cfSriastradh{
144542542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
144603b705cfSriastradh	const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
144703b705cfSriastradh	Bool dummy;
144803b705cfSriastradh
144903b705cfSriastradh	if (s == NULL || xf86getBoolValue(&dummy, s)) {
145003b705cfSriastradh		if (INTEL_INFO(intel)->gen < 030)
145103b705cfSriastradh			return has_i830_dri() ? "i830" : "i915";
145203b705cfSriastradh		else if (INTEL_INFO(intel)->gen < 040)
145303b705cfSriastradh			return "i915";
145403b705cfSriastradh		else
145503b705cfSriastradh			return "i965";
145603b705cfSriastradh	}
145703b705cfSriastradh
145803b705cfSriastradh	return s;
145942542f5fSchristos#else
146042542f5fSchristos	if (INTEL_INFO(intel)->gen < 030)
146142542f5fSchristos		return has_i830_dri() ? "i830" : "i915";
146242542f5fSchristos	else if (INTEL_INFO(intel)->gen < 040)
146342542f5fSchristos		return "i915";
146442542f5fSchristos	else
146542542f5fSchristos		return "i965";
146642542f5fSchristos#endif
146703b705cfSriastradh}
146803b705cfSriastradh
146903b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen)
147003b705cfSriastradh{
147103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
147203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
147303b705cfSriastradh	DRI2InfoRec info;
147442542f5fSchristos	int dri2scr_major = 1;
147542542f5fSchristos	int dri2scr_minor = 0;
147603b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
147742542f5fSchristos	const char *driverNames[2];
147803b705cfSriastradh#endif
147903b705cfSriastradh
148003b705cfSriastradh	if (intel->force_fallback) {
148103b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
148203b705cfSriastradh			   "cannot enable DRI2 whilst forcing software fallbacks\n");
148303b705cfSriastradh		return FALSE;
148403b705cfSriastradh	}
148503b705cfSriastradh
148603b705cfSriastradh	if (xf86LoaderCheckSymbol("DRI2Version"))
148742542f5fSchristos		DRI2Version(&dri2scr_major, &dri2scr_minor);
148803b705cfSriastradh
148942542f5fSchristos	if (dri2scr_minor < 1) {
149003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
149103b705cfSriastradh			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
149203b705cfSriastradh		return FALSE;
149303b705cfSriastradh	}
149403b705cfSriastradh
149503b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
149603b705cfSriastradh	if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID)))
149703b705cfSriastradh		return FALSE;
149803b705cfSriastradh#else
149903b705cfSriastradh	if (!dixRequestPrivate(&i830_client_key, sizeof(XID)))
150003b705cfSriastradh		return FALSE;
150103b705cfSriastradh#endif
150203b705cfSriastradh
150303b705cfSriastradh
150403b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
150503b705cfSriastradh	if (serverGeneration != dri2_server_generation) {
150603b705cfSriastradh	    dri2_server_generation = serverGeneration;
150703b705cfSriastradh	    if (!i830_dri2_register_frame_event_resource_types()) {
150803b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
150903b705cfSriastradh			   "Cannot register DRI2 frame event resources\n");
151003b705cfSriastradh		return FALSE;
151103b705cfSriastradh	    }
151203b705cfSriastradh	}
151303b705cfSriastradh#endif
151403b705cfSriastradh
151503b705cfSriastradh	intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD);
151603b705cfSriastradh	memset(&info, '\0', sizeof(info));
151703b705cfSriastradh	info.fd = intel->drmSubFD;
151803b705cfSriastradh	info.driverName = dri_driver_name(intel);
151903b705cfSriastradh	info.deviceName = intel->deviceName;
152003b705cfSriastradh
152103b705cfSriastradh#if DRI2INFOREC_VERSION == 1
152203b705cfSriastradh	info.version = 1;
152303b705cfSriastradh	info.CreateBuffers = I830DRI2CreateBuffers;
152403b705cfSriastradh	info.DestroyBuffers = I830DRI2DestroyBuffers;
152503b705cfSriastradh#elif DRI2INFOREC_VERSION == 2
152603b705cfSriastradh	/* The ABI between 2 and 3 was broken so we could get rid of
152703b705cfSriastradh	 * the multi-buffer alloc functions.  Make sure we indicate the
152803b705cfSriastradh	 * right version so DRI2 can reject us if it's version 3 or above. */
152903b705cfSriastradh	info.version = 2;
153003b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
153103b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
153203b705cfSriastradh#else
153303b705cfSriastradh	info.version = 3;
153403b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
153503b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
153603b705cfSriastradh#endif
153703b705cfSriastradh
153803b705cfSriastradh	info.CopyRegion = I830DRI2CopyRegion;
153903b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
154003b705cfSriastradh	info.version = 4;
154103b705cfSriastradh	info.ScheduleSwap = I830DRI2ScheduleSwap;
154203b705cfSriastradh	info.GetMSC = I830DRI2GetMSC;
154303b705cfSriastradh	info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
154442542f5fSchristos	info.numDrivers = 2;
154503b705cfSriastradh	info.driverNames = driverNames;
154603b705cfSriastradh	driverNames[0] = info.driverName;
154742542f5fSchristos	driverNames[1] = info.driverName;
154803b705cfSriastradh#endif
154903b705cfSriastradh
155003b705cfSriastradh	return DRI2ScreenInit(screen, &info);
155103b705cfSriastradh}
155203b705cfSriastradh
155303b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen)
155403b705cfSriastradh{
155503b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
155603b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
155703b705cfSriastradh
155803b705cfSriastradh	DRI2CloseScreen(screen);
155903b705cfSriastradh	drmFree(intel->deviceName);
156003b705cfSriastradh}
1561