intel_dri.c revision 42542f5f
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
6903b705cfSriastradh#include "intel_glamor.h"
7003b705cfSriastradh#include "uxa.h"
7103b705cfSriastradh
7203b705cfSriastradhtypedef struct {
7303b705cfSriastradh	int refcnt;
7403b705cfSriastradh	PixmapPtr pixmap;
7503b705cfSriastradh} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
7603b705cfSriastradh
7703b705cfSriastradh#if HAS_DEVPRIVATEKEYREC
7803b705cfSriastradhstatic DevPrivateKeyRec i830_client_key;
7903b705cfSriastradh#else
8003b705cfSriastradhstatic int i830_client_key;
8103b705cfSriastradh#endif
8203b705cfSriastradh
8303b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap)
8403b705cfSriastradh{
8503b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
8603b705cfSriastradh	uint32_t name;
8703b705cfSriastradh
8803b705cfSriastradh	if (priv == NULL || priv->bo == NULL)
8903b705cfSriastradh		return 0;
9003b705cfSriastradh
9103b705cfSriastradh	if (dri_bo_flink(priv->bo, &name) != 0)
9203b705cfSriastradh		return 0;
9303b705cfSriastradh
9442542f5fSchristos	priv->pinned |= PIN_DRI2;
9503b705cfSriastradh	return name;
9603b705cfSriastradh}
9703b705cfSriastradh
9803b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable)
9903b705cfSriastradh{
10003b705cfSriastradh	PixmapPtr pixmap;
10103b705cfSriastradh
10203b705cfSriastradh	pixmap = get_drawable_pixmap(drawable);
10303b705cfSriastradh	if (!intel_get_pixmap_bo(pixmap))
10403b705cfSriastradh		return NULL;
10503b705cfSriastradh
10603b705cfSriastradh	pixmap->refcnt++;
10703b705cfSriastradh	return pixmap;
10803b705cfSriastradh}
10903b705cfSriastradh
11003b705cfSriastradhstatic PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap)
11103b705cfSriastradh{
11203b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
11303b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
11403b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
11503b705cfSriastradh	PixmapPtr old = get_drawable_pixmap(drawable);
11603b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
11703b705cfSriastradh	GCPtr gc;
11803b705cfSriastradh
11903b705cfSriastradh	/* With a glamor pixmap, 2D pixmaps are created in texture
12003b705cfSriastradh	 * and without a static BO attached to it. To support DRI,
12103b705cfSriastradh	 * we need to create a new textured-drm pixmap and
12203b705cfSriastradh	 * need to copy the original content to this new textured-drm
12303b705cfSriastradh	 * pixmap, and then convert the old pixmap to a coherent
12403b705cfSriastradh	 * textured-drm pixmap which has a valid BO attached to it
12503b705cfSriastradh	 * and also has a valid texture, thus both glamor and DRI2
12603b705cfSriastradh	 * can access it.
12703b705cfSriastradh	 *
12803b705cfSriastradh	 */
12903b705cfSriastradh
13003b705cfSriastradh	/* Copy the current contents of the pixmap to the bo. */
13103b705cfSriastradh	gc = GetScratchGC(drawable->depth, screen);
13203b705cfSriastradh	if (gc) {
13303b705cfSriastradh		ValidateGC(&pixmap->drawable, gc);
13403b705cfSriastradh		gc->ops->CopyArea(drawable, &pixmap->drawable,
13503b705cfSriastradh				  gc,
13603b705cfSriastradh				  0, 0,
13703b705cfSriastradh				  drawable->width,
13803b705cfSriastradh				  drawable->height,
13903b705cfSriastradh				  0, 0);
14003b705cfSriastradh		FreeScratchGC(gc);
14103b705cfSriastradh	}
14203b705cfSriastradh
14303b705cfSriastradh	intel_set_pixmap_private(pixmap, NULL);
14403b705cfSriastradh
14503b705cfSriastradh	/* Exchange the underlying texture/image. */
14603b705cfSriastradh	intel_glamor_exchange_buffers(intel, old, pixmap);
14703b705cfSriastradh	/* And redirect the pixmap to the new bo (for 3D). */
14803b705cfSriastradh	intel_set_pixmap_private(old, priv);
14903b705cfSriastradh	old->refcnt++;
15003b705cfSriastradh
15103b705cfSriastradh	screen->ModifyPixmapHeader(old,
15203b705cfSriastradh				   drawable->width,
15303b705cfSriastradh				   drawable->height,
15403b705cfSriastradh				   0, 0,
15503b705cfSriastradh				   priv->stride,
15603b705cfSriastradh				   NULL);
15703b705cfSriastradh	screen->DestroyPixmap(pixmap);
15803b705cfSriastradh	intel_get_screen_private(xf86ScreenToScrn(screen))->needs_flush = TRUE;
15903b705cfSriastradh	return old;
16003b705cfSriastradh}
16103b705cfSriastradh
16203b705cfSriastradh#if DRI2INFOREC_VERSION < 2
16303b705cfSriastradhstatic DRI2BufferPtr
16403b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
16503b705cfSriastradh		      int count)
16603b705cfSriastradh{
16703b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
16803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
16903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
17003b705cfSriastradh	DRI2BufferPtr buffers;
17103b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
17203b705cfSriastradh	PixmapPtr pixmap, pDepthPixmap;
17303b705cfSriastradh	Bool is_glamor_pixmap = FALSE;
17403b705cfSriastradh	int i;
17503b705cfSriastradh
17603b705cfSriastradh	buffers = calloc(count, sizeof *buffers);
17703b705cfSriastradh	if (buffers == NULL)
17803b705cfSriastradh		return NULL;
17903b705cfSriastradh	privates = calloc(count, sizeof *privates);
18003b705cfSriastradh	if (privates == NULL) {
18103b705cfSriastradh		free(buffers);
18203b705cfSriastradh		return NULL;
18303b705cfSriastradh	}
18403b705cfSriastradh
18503b705cfSriastradh	pDepthPixmap = NULL;
18603b705cfSriastradh	for (i = 0; i < count; i++) {
18703b705cfSriastradh		pixmap = NULL;
18803b705cfSriastradh		if (attachments[i] == DRI2BufferFrontLeft) {
18903b705cfSriastradh			pixmap = get_front_buffer(drawable);
19003b705cfSriastradh
19103b705cfSriastradh			if (pixmap == NULL) {
19203b705cfSriastradh				drawable = &(get_drawable_pixmap(drawable)->drawable);
19303b705cfSriastradh				is_glamor_pixmap = TRUE;
19403b705cfSriastradh			}
19503b705cfSriastradh		} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
19603b705cfSriastradh			pixmap = pDepthPixmap;
19703b705cfSriastradh			pixmap->refcnt++;
19803b705cfSriastradh		}
19903b705cfSriastradh
20003b705cfSriastradh		if (pixmap == NULL) {
20103b705cfSriastradh			unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
20203b705cfSriastradh
20303b705cfSriastradh			if (intel->tiling & INTEL_TILING_3D) {
20403b705cfSriastradh				switch (attachments[i]) {
20503b705cfSriastradh				case DRI2BufferDepth:
20603b705cfSriastradh					if (SUPPORTS_YTILING(intel))
20703b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_Y;
20803b705cfSriastradh					else
20903b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_X;
21003b705cfSriastradh					break;
21103b705cfSriastradh				case DRI2BufferFakeFrontLeft:
21203b705cfSriastradh				case DRI2BufferFakeFrontRight:
21303b705cfSriastradh				case DRI2BufferBackLeft:
21403b705cfSriastradh				case DRI2BufferBackRight:
21503b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_X;
21603b705cfSriastradh					break;
21703b705cfSriastradh				}
21803b705cfSriastradh			}
21903b705cfSriastradh
22003b705cfSriastradh			pixmap = screen->CreatePixmap(screen,
22103b705cfSriastradh						      drawable->width,
22203b705cfSriastradh						      drawable->height,
22303b705cfSriastradh						      drawable->depth,
22403b705cfSriastradh						      hint);
22503b705cfSriastradh			if (pixmap == NULL ||
22603b705cfSriastradh			    intel_get_pixmap_bo(pixmap) == NULL)
22703b705cfSriastradh			{
22803b705cfSriastradh				if (pixmap)
22903b705cfSriastradh					screen->DestroyPixmap(pixmap);
23003b705cfSriastradh				goto unwind;
23103b705cfSriastradh			}
23203b705cfSriastradh
23303b705cfSriastradh			if (is_glamor_pixmap)
23403b705cfSriastradh				pixmap = fixup_glamor(drawable, pixmap);
23503b705cfSriastradh		}
23603b705cfSriastradh
23703b705cfSriastradh		if (attachments[i] == DRI2BufferDepth)
23803b705cfSriastradh			pDepthPixmap = pixmap;
23903b705cfSriastradh
24003b705cfSriastradh		buffers[i].attachment = attachments[i];
24103b705cfSriastradh		buffers[i].pitch = pixmap->devKind;
24203b705cfSriastradh		buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
24303b705cfSriastradh		buffers[i].driverPrivate = &privates[i];
24403b705cfSriastradh		buffers[i].flags = 0;	/* not tiled */
24503b705cfSriastradh		privates[i].refcnt = 1;
24603b705cfSriastradh		privates[i].pixmap = pixmap;
24703b705cfSriastradh
24803b705cfSriastradh		if ((buffers[i].name = pixmap_flink(pixmap)) == 0) {
24903b705cfSriastradh			/* failed to name buffer */
25003b705cfSriastradh			screen->DestroyPixmap(pixmap);
25103b705cfSriastradh			goto unwind;
25203b705cfSriastradh		}
25303b705cfSriastradh	}
25403b705cfSriastradh
25503b705cfSriastradh	return buffers;
25603b705cfSriastradh
25703b705cfSriastradhunwind:
25803b705cfSriastradh	while (i--)
25903b705cfSriastradh		screen->DestroyPixmap(privates[i].pixmap);
26003b705cfSriastradh	free(privates);
26103b705cfSriastradh	free(buffers);
26203b705cfSriastradh	return NULL;
26303b705cfSriastradh}
26403b705cfSriastradh
26503b705cfSriastradhstatic void
26603b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
26703b705cfSriastradh{
26803b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
26903b705cfSriastradh	I830DRI2BufferPrivatePtr private;
27003b705cfSriastradh	int i;
27103b705cfSriastradh
27203b705cfSriastradh	for (i = 0; i < count; i++) {
27303b705cfSriastradh		private = buffers[i].driverPrivate;
27403b705cfSriastradh		screen->DestroyPixmap(private->pixmap);
27503b705cfSriastradh	}
27603b705cfSriastradh
27703b705cfSriastradh	if (buffers) {
27803b705cfSriastradh		free(buffers[0].driverPrivate);
27903b705cfSriastradh		free(buffers);
28003b705cfSriastradh	}
28103b705cfSriastradh}
28203b705cfSriastradh
28303b705cfSriastradh#else
28403b705cfSriastradh
28503b705cfSriastradhstatic DRI2Buffer2Ptr
28603b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
28703b705cfSriastradh		     unsigned int format)
28803b705cfSriastradh{
28903b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
29003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
29103b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
29203b705cfSriastradh	DRI2Buffer2Ptr buffer;
29303b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
29403b705cfSriastradh	PixmapPtr pixmap;
29503b705cfSriastradh	Bool is_glamor_pixmap = FALSE;
29603b705cfSriastradh
29703b705cfSriastradh	buffer = calloc(1, sizeof *buffer);
29803b705cfSriastradh	if (buffer == NULL)
29903b705cfSriastradh		return NULL;
30003b705cfSriastradh	privates = calloc(1, sizeof *privates);
30103b705cfSriastradh	if (privates == NULL) {
30203b705cfSriastradh		free(buffer);
30303b705cfSriastradh		return NULL;
30403b705cfSriastradh	}
30503b705cfSriastradh
30603b705cfSriastradh	pixmap = NULL;
30703b705cfSriastradh	if (attachment == DRI2BufferFrontLeft) {
30803b705cfSriastradh		pixmap = get_front_buffer(drawable);
30903b705cfSriastradh
31003b705cfSriastradh		if (pixmap == NULL) {
31103b705cfSriastradh			drawable = &(get_drawable_pixmap(drawable)->drawable);
31203b705cfSriastradh			is_glamor_pixmap = TRUE;
31303b705cfSriastradh		}
31403b705cfSriastradh	}
31503b705cfSriastradh
31603b705cfSriastradh	if (pixmap == NULL) {
31703b705cfSriastradh		unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
31803b705cfSriastradh		int pixmap_width = drawable->width;
31903b705cfSriastradh		int pixmap_height = drawable->height;
32003b705cfSriastradh		int pixmap_cpp = (format != 0) ? format : drawable->depth;
32103b705cfSriastradh
32203b705cfSriastradh		if (intel->tiling & INTEL_TILING_3D) {
32303b705cfSriastradh			switch (attachment) {
32403b705cfSriastradh			case DRI2BufferDepth:
32503b705cfSriastradh			case DRI2BufferDepthStencil:
32603b705cfSriastradh			case DRI2BufferHiz:
32703b705cfSriastradh				if (SUPPORTS_YTILING(intel)) {
32803b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_Y;
32903b705cfSriastradh					break;
33003b705cfSriastradh				}
33103b705cfSriastradh			case DRI2BufferAccum:
33203b705cfSriastradh			case DRI2BufferBackLeft:
33303b705cfSriastradh			case DRI2BufferBackRight:
33403b705cfSriastradh			case DRI2BufferFakeFrontLeft:
33503b705cfSriastradh			case DRI2BufferFakeFrontRight:
33603b705cfSriastradh			case DRI2BufferFrontLeft:
33703b705cfSriastradh			case DRI2BufferFrontRight:
33803b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_X;
33903b705cfSriastradh				break;
34003b705cfSriastradh			case DRI2BufferStencil:
34103b705cfSriastradh				/*
34203b705cfSriastradh				 * The stencil buffer is W tiled. However, we
34303b705cfSriastradh				 * request from the kernel a non-tiled buffer
34403b705cfSriastradh				 * because the GTT is incapable of W fencing.
34503b705cfSriastradh				 */
34603b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_NONE;
34703b705cfSriastradh				break;
34803b705cfSriastradh			default:
34903b705cfSriastradh				free(privates);
35003b705cfSriastradh				free(buffer);
35103b705cfSriastradh				return NULL;
35203b705cfSriastradh                        }
35303b705cfSriastradh		}
35403b705cfSriastradh
35503b705cfSriastradh		/*
35603b705cfSriastradh		 * The stencil buffer has quirky pitch requirements.  From Vol
35703b705cfSriastradh		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
35803b705cfSriastradh		 * Pitch":
35903b705cfSriastradh		 *    The pitch must be set to 2x the value computed based on
36003b705cfSriastradh		 *    width, as the stencil buffer is stored with two rows
36103b705cfSriastradh		 *    interleaved.
36203b705cfSriastradh		 * To accomplish this, we resort to the nasty hack of doubling
36303b705cfSriastradh		 * the drm region's cpp and halving its height.
36403b705cfSriastradh		 *
36503b705cfSriastradh		 * If we neglect to double the pitch, then render corruption
36603b705cfSriastradh		 * occurs.
36703b705cfSriastradh		 */
36803b705cfSriastradh		if (attachment == DRI2BufferStencil) {
36903b705cfSriastradh			pixmap_width = ALIGN(pixmap_width, 64);
37003b705cfSriastradh			pixmap_height = ALIGN((pixmap_height + 1) / 2, 64);
37103b705cfSriastradh			pixmap_cpp *= 2;
37203b705cfSriastradh		}
37303b705cfSriastradh
37403b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
37503b705cfSriastradh					      pixmap_width,
37603b705cfSriastradh					      pixmap_height,
37703b705cfSriastradh					      pixmap_cpp,
37803b705cfSriastradh					      hint);
37903b705cfSriastradh		if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) {
38003b705cfSriastradh			if (pixmap)
38103b705cfSriastradh				screen->DestroyPixmap(pixmap);
38203b705cfSriastradh			free(privates);
38303b705cfSriastradh			free(buffer);
38403b705cfSriastradh			return NULL;
38503b705cfSriastradh		}
38603b705cfSriastradh		if (is_glamor_pixmap)
38703b705cfSriastradh			pixmap = fixup_glamor(drawable, pixmap);
38803b705cfSriastradh	}
38903b705cfSriastradh
39003b705cfSriastradh	buffer->attachment = attachment;
39103b705cfSriastradh	buffer->pitch = pixmap->devKind;
39203b705cfSriastradh	buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
39303b705cfSriastradh	buffer->driverPrivate = privates;
39403b705cfSriastradh	buffer->format = format;
39503b705cfSriastradh	buffer->flags = 0;	/* not tiled */
39603b705cfSriastradh	privates->refcnt = 1;
39703b705cfSriastradh	privates->pixmap = pixmap;
39803b705cfSriastradh
39903b705cfSriastradh	if ((buffer->name = pixmap_flink(pixmap)) == 0) {
40003b705cfSriastradh		/* failed to name buffer */
40103b705cfSriastradh		screen->DestroyPixmap(pixmap);
40203b705cfSriastradh		free(privates);
40303b705cfSriastradh		free(buffer);
40403b705cfSriastradh		return NULL;
40503b705cfSriastradh	}
40603b705cfSriastradh
40703b705cfSriastradh	return buffer;
40803b705cfSriastradh}
40903b705cfSriastradh
41003b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
41103b705cfSriastradh{
41203b705cfSriastradh	if (buffer && buffer->driverPrivate) {
41303b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
41403b705cfSriastradh		if (--private->refcnt == 0) {
41503b705cfSriastradh			ScreenPtr screen = private->pixmap->drawable.pScreen;
41603b705cfSriastradh			screen->DestroyPixmap(private->pixmap);
41703b705cfSriastradh
41803b705cfSriastradh			free(private);
41903b705cfSriastradh			free(buffer);
42003b705cfSriastradh		}
42103b705cfSriastradh	} else
42203b705cfSriastradh		free(buffer);
42303b705cfSriastradh}
42403b705cfSriastradh
42503b705cfSriastradh#endif
42603b705cfSriastradh
42703b705cfSriastradhstatic void
42803b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
42903b705cfSriastradh		   DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
43003b705cfSriastradh{
43103b705cfSriastradh	I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate;
43203b705cfSriastradh	I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate;
43303b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
43403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
43503b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
43603b705cfSriastradh	DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
43703b705cfSriastradh		? drawable : &srcPrivate->pixmap->drawable;
43803b705cfSriastradh	DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
43903b705cfSriastradh		? drawable : &dstPrivate->pixmap->drawable;
44003b705cfSriastradh	RegionPtr pCopyClip;
44103b705cfSriastradh	GCPtr gc;
44203b705cfSriastradh
44303b705cfSriastradh	gc = GetScratchGC(dst->depth, screen);
44403b705cfSriastradh	if (!gc)
44503b705cfSriastradh		return;
44603b705cfSriastradh
44703b705cfSriastradh	pCopyClip = REGION_CREATE(screen, NULL, 0);
44803b705cfSriastradh	REGION_COPY(screen, pCopyClip, pRegion);
44903b705cfSriastradh	(*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
45003b705cfSriastradh	ValidateGC(dst, gc);
45103b705cfSriastradh
45203b705cfSriastradh	/* Wait for the scanline to be outside the region to be copied */
45303b705cfSriastradh	if (scrn->vtSema &&
45403b705cfSriastradh	    pixmap_is_scanout(get_drawable_pixmap(dst)) &&
45503b705cfSriastradh	    intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) {
45603b705cfSriastradh		BoxPtr box;
45703b705cfSriastradh		BoxRec crtcbox;
45803b705cfSriastradh		int y1, y2;
45903b705cfSriastradh		int event, load_scan_lines_pipe;
46003b705cfSriastradh		xf86CrtcPtr crtc;
46103b705cfSriastradh		Bool full_height = FALSE;
46203b705cfSriastradh
46303b705cfSriastradh		box = REGION_EXTENTS(unused, gc->pCompositeClip);
46403b705cfSriastradh		crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox);
46503b705cfSriastradh
46603b705cfSriastradh		/*
46703b705cfSriastradh		 * Make sure the CRTC is valid and this is the real front
46803b705cfSriastradh		 * buffer
46903b705cfSriastradh		 */
47003b705cfSriastradh		if (crtc != NULL && !crtc->rotatedData) {
47103b705cfSriastradh			int pipe = intel_crtc_to_pipe(crtc);
47203b705cfSriastradh
47303b705cfSriastradh			/*
47403b705cfSriastradh			 * Make sure we don't wait for a scanline that will
47503b705cfSriastradh			 * never occur
47603b705cfSriastradh			 */
47703b705cfSriastradh			y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
47803b705cfSriastradh			y2 = (box->y2 <= crtcbox.y2) ?
47903b705cfSriastradh			    box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
48003b705cfSriastradh
48103b705cfSriastradh			if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1))
48203b705cfSriastradh			    full_height = TRUE;
48303b705cfSriastradh
48403b705cfSriastradh			/*
48503b705cfSriastradh			 * Pre-965 doesn't have SVBLANK, so we need a bit
48603b705cfSriastradh			 * of extra time for the blitter to start up and
48703b705cfSriastradh			 * do its job for a full height blit
48803b705cfSriastradh			 */
48903b705cfSriastradh			if (full_height && INTEL_INFO(intel)->gen < 040)
49003b705cfSriastradh			    y2 -= 2;
49103b705cfSriastradh
49203b705cfSriastradh			if (pipe == 0) {
49303b705cfSriastradh				event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
49403b705cfSriastradh				load_scan_lines_pipe =
49503b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
49603b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
49703b705cfSriastradh				    event = MI_WAIT_FOR_PIPEA_SVBLANK;
49803b705cfSriastradh			} else {
49903b705cfSriastradh				event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
50003b705cfSriastradh				load_scan_lines_pipe =
50103b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
50203b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
50303b705cfSriastradh				    event = MI_WAIT_FOR_PIPEB_SVBLANK;
50403b705cfSriastradh			}
50503b705cfSriastradh
50603b705cfSriastradh			if (crtc->mode.Flags & V_INTERLACE) {
50703b705cfSriastradh				/* DSL count field lines */
50803b705cfSriastradh				y1 /= 2;
50903b705cfSriastradh				y2 /= 2;
51003b705cfSriastradh			}
51103b705cfSriastradh
51203b705cfSriastradh			BEGIN_BATCH(5);
51303b705cfSriastradh			/*
51403b705cfSriastradh			 * The documentation says that the LOAD_SCAN_LINES
51503b705cfSriastradh			 * command always comes in pairs. Don't ask me why.
51603b705cfSriastradh			 */
51703b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
51803b705cfSriastradh				  load_scan_lines_pipe);
51903b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
52003b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
52103b705cfSriastradh				  load_scan_lines_pipe);
52203b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
52303b705cfSriastradh			OUT_BATCH(MI_WAIT_FOR_EVENT | event);
52403b705cfSriastradh			ADVANCE_BATCH();
52503b705cfSriastradh		}
52603b705cfSriastradh	}
52703b705cfSriastradh
52803b705cfSriastradh	/* It's important that this copy gets submitted before the
52903b705cfSriastradh	 * direct rendering client submits rendering for the next
53003b705cfSriastradh	 * frame, but we don't actually need to submit right now.  The
53103b705cfSriastradh	 * client will wait for the DRI2CopyRegion reply or the swap
53203b705cfSriastradh	 * buffer event before rendering, and we'll hit the flush
53303b705cfSriastradh	 * callback chain before those messages are sent.  We submit
53403b705cfSriastradh	 * our batch buffers from the flush callback chain so we know
53503b705cfSriastradh	 * that will happen before the client tries to render
53603b705cfSriastradh	 * again. */
53703b705cfSriastradh
53803b705cfSriastradh	gc->ops->CopyArea(src, dst, gc,
53903b705cfSriastradh			  0, 0,
54003b705cfSriastradh			  drawable->width, drawable->height,
54103b705cfSriastradh			  0, 0);
54203b705cfSriastradh
54303b705cfSriastradh	FreeScratchGC(gc);
54403b705cfSriastradh
54503b705cfSriastradh	/* And make sure the WAIT_FOR_EVENT is queued before any
54603b705cfSriastradh	 * modesetting/dpms operations on the pipe.
54703b705cfSriastradh	 */
54803b705cfSriastradh	intel_batch_submit(scrn);
54903b705cfSriastradh}
55003b705cfSriastradh
55103b705cfSriastradhstatic void
55203b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable,
55303b705cfSriastradh			 DRI2BufferPtr dst,
55403b705cfSriastradh			 DRI2BufferPtr src)
55503b705cfSriastradh{
55603b705cfSriastradh	BoxRec box;
55703b705cfSriastradh	RegionRec region;
55803b705cfSriastradh
55903b705cfSriastradh	box.x1 = 0;
56003b705cfSriastradh	box.y1 = 0;
56103b705cfSriastradh	box.x2 = drawable->width;
56203b705cfSriastradh	box.y2 = drawable->height;
56303b705cfSriastradh	REGION_INIT(pScreen, &region, &box, 0);
56403b705cfSriastradh
56503b705cfSriastradh	I830DRI2CopyRegion(drawable, &region, dst, src);
56603b705cfSriastradh}
56703b705cfSriastradh
56803b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
56903b705cfSriastradh
57003b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
57103b705cfSriastradh{
57203b705cfSriastradh	if (buffer) {
57303b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
57403b705cfSriastradh		private->refcnt++;
57503b705cfSriastradh	}
57603b705cfSriastradh}
57703b705cfSriastradh
57842542f5fSchristosstatic xf86CrtcPtr
57942542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw)
58003b705cfSriastradh{
58103b705cfSriastradh	ScreenPtr pScreen = pDraw->pScreen;
58203b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
58303b705cfSriastradh	BoxRec box, crtcbox;
58442542f5fSchristos	xf86CrtcPtr crtc = NULL;
58503b705cfSriastradh
58603b705cfSriastradh	box.x1 = pDraw->x;
58703b705cfSriastradh	box.y1 = pDraw->y;
58803b705cfSriastradh	box.x2 = box.x1 + pDraw->width;
58903b705cfSriastradh	box.y2 = box.y1 + pDraw->height;
59003b705cfSriastradh
59142542f5fSchristos	if (pDraw->type != DRAWABLE_PIXMAP)
59242542f5fSchristos		crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
59303b705cfSriastradh
59403b705cfSriastradh	/* Make sure the CRTC is valid and this is the real front buffer */
59503b705cfSriastradh	if (crtc != NULL && !crtc->rotatedData)
59642542f5fSchristos                return crtc;
59703b705cfSriastradh
59842542f5fSchristos	return NULL;
59903b705cfSriastradh}
60003b705cfSriastradh
60103b705cfSriastradhstatic RESTYPE	frame_event_client_type, frame_event_drawable_type;
60203b705cfSriastradh
60303b705cfSriastradhstruct i830_dri2_resource {
60403b705cfSriastradh	XID id;
60503b705cfSriastradh	RESTYPE type;
60603b705cfSriastradh	struct list list;
60703b705cfSriastradh};
60803b705cfSriastradh
60903b705cfSriastradhstatic struct i830_dri2_resource *
61003b705cfSriastradhget_resource(XID id, RESTYPE type)
61103b705cfSriastradh{
61203b705cfSriastradh	struct i830_dri2_resource *resource;
61303b705cfSriastradh	void *ptr;
61403b705cfSriastradh
61503b705cfSriastradh	ptr = NULL;
61603b705cfSriastradh	dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
61703b705cfSriastradh	if (ptr)
61803b705cfSriastradh		return ptr;
61903b705cfSriastradh
62003b705cfSriastradh	resource = malloc(sizeof(*resource));
62103b705cfSriastradh	if (resource == NULL)
62203b705cfSriastradh		return NULL;
62303b705cfSriastradh
62403b705cfSriastradh	if (!AddResource(id, type, resource)) {
62503b705cfSriastradh		free(resource);
62603b705cfSriastradh		return NULL;
62703b705cfSriastradh	}
62803b705cfSriastradh
62903b705cfSriastradh	resource->id = id;
63003b705cfSriastradh	resource->type = type;
63103b705cfSriastradh	list_init(&resource->list);
63203b705cfSriastradh	return resource;
63303b705cfSriastradh}
63403b705cfSriastradh
63503b705cfSriastradhstatic int
63603b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id)
63703b705cfSriastradh{
63803b705cfSriastradh	struct i830_dri2_resource *resource = data;
63903b705cfSriastradh
64003b705cfSriastradh	while (!list_is_empty(&resource->list)) {
64103b705cfSriastradh		DRI2FrameEventPtr info =
64203b705cfSriastradh			list_first_entry(&resource->list,
64303b705cfSriastradh					 DRI2FrameEventRec,
64403b705cfSriastradh					 client_resource);
64503b705cfSriastradh
64603b705cfSriastradh		list_del(&info->client_resource);
64703b705cfSriastradh		info->client = NULL;
64803b705cfSriastradh	}
64903b705cfSriastradh	free(resource);
65003b705cfSriastradh
65103b705cfSriastradh	return Success;
65203b705cfSriastradh}
65303b705cfSriastradh
65403b705cfSriastradhstatic int
65503b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id)
65603b705cfSriastradh{
65703b705cfSriastradh	struct i830_dri2_resource *resource = data;
65803b705cfSriastradh
65903b705cfSriastradh	while (!list_is_empty(&resource->list)) {
66003b705cfSriastradh		DRI2FrameEventPtr info =
66103b705cfSriastradh			list_first_entry(&resource->list,
66203b705cfSriastradh					 DRI2FrameEventRec,
66303b705cfSriastradh					 drawable_resource);
66403b705cfSriastradh
66503b705cfSriastradh		list_del(&info->drawable_resource);
66603b705cfSriastradh		info->drawable_id = None;
66703b705cfSriastradh	}
66803b705cfSriastradh	free(resource);
66903b705cfSriastradh
67003b705cfSriastradh	return Success;
67103b705cfSriastradh}
67203b705cfSriastradh
67303b705cfSriastradhstatic Bool
67403b705cfSriastradhi830_dri2_register_frame_event_resource_types(void)
67503b705cfSriastradh{
67603b705cfSriastradh	frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client");
67703b705cfSriastradh	if (!frame_event_client_type)
67803b705cfSriastradh		return FALSE;
67903b705cfSriastradh
68003b705cfSriastradh	frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable");
68103b705cfSriastradh	if (!frame_event_drawable_type)
68203b705cfSriastradh		return FALSE;
68303b705cfSriastradh
68403b705cfSriastradh	return TRUE;
68503b705cfSriastradh}
68603b705cfSriastradh
68703b705cfSriastradhstatic XID
68803b705cfSriastradhget_client_id(ClientPtr client)
68903b705cfSriastradh{
69003b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
69103b705cfSriastradh	XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key);
69203b705cfSriastradh#else
69303b705cfSriastradh	XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key);
69403b705cfSriastradh#endif
69503b705cfSriastradh	if (*ptr == 0)
69603b705cfSriastradh		*ptr = FakeClientID(client->index);
69703b705cfSriastradh	return *ptr;
69803b705cfSriastradh}
69903b705cfSriastradh
70003b705cfSriastradh/*
70103b705cfSriastradh * Hook this frame event into the server resource
70203b705cfSriastradh * database so we can clean it up if the drawable or
70303b705cfSriastradh * client exits while the swap is pending
70403b705cfSriastradh */
70503b705cfSriastradhstatic Bool
70603b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info)
70703b705cfSriastradh{
70803b705cfSriastradh	struct i830_dri2_resource *resource;
70903b705cfSriastradh
71003b705cfSriastradh	resource = get_resource(get_client_id(info->client),
71103b705cfSriastradh				frame_event_client_type);
71203b705cfSriastradh	if (resource == NULL)
71303b705cfSriastradh		return FALSE;
71403b705cfSriastradh
71503b705cfSriastradh	list_add(&info->client_resource, &resource->list);
71603b705cfSriastradh
71703b705cfSriastradh	resource = get_resource(info->drawable_id, frame_event_drawable_type);
71803b705cfSriastradh	if (resource == NULL) {
71903b705cfSriastradh		list_del(&info->client_resource);
72003b705cfSriastradh		return FALSE;
72103b705cfSriastradh	}
72203b705cfSriastradh
72303b705cfSriastradh	list_add(&info->drawable_resource, &resource->list);
72403b705cfSriastradh
72503b705cfSriastradh	return TRUE;
72603b705cfSriastradh}
72703b705cfSriastradh
72803b705cfSriastradhstatic void
72942542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info)
73003b705cfSriastradh{
73103b705cfSriastradh	list_del(&info->client_resource);
73203b705cfSriastradh	list_del(&info->drawable_resource);
73303b705cfSriastradh
73403b705cfSriastradh	if (info->front)
73542542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->front);
73603b705cfSriastradh	if (info->back)
73742542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->back);
73803b705cfSriastradh
73903b705cfSriastradh	free(info);
74003b705cfSriastradh}
74103b705cfSriastradh
74203b705cfSriastradhstatic struct intel_pixmap *
74303b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back)
74403b705cfSriastradh{
74503b705cfSriastradh	struct intel_pixmap *new_front, *new_back;
74603b705cfSriastradh	RegionRec region;
74703b705cfSriastradh
74803b705cfSriastradh	/* Post damage on the front buffer so that listeners, such
74903b705cfSriastradh	 * as DisplayLink know take a copy and shove it over the USB.
75003b705cfSriastradh	 * also for sw cursors.
75103b705cfSriastradh	 */
75203b705cfSriastradh	region.extents.x1 = region.extents.y1 = 0;
75303b705cfSriastradh	region.extents.x2 = front->drawable.width;
75403b705cfSriastradh	region.extents.y2 = front->drawable.height;
75503b705cfSriastradh	region.data = NULL;
75603b705cfSriastradh	DamageRegionAppend(&front->drawable, &region);
75703b705cfSriastradh
75803b705cfSriastradh	new_front = intel_get_pixmap_private(back);
75903b705cfSriastradh	new_back = intel_get_pixmap_private(front);
76003b705cfSriastradh	intel_set_pixmap_private(front, new_front);
76103b705cfSriastradh	intel_set_pixmap_private(back, new_back);
76203b705cfSriastradh	new_front->busy = 1;
76303b705cfSriastradh	new_back->busy = -1;
76403b705cfSriastradh
76503b705cfSriastradh	intel_glamor_exchange_buffers(intel, front, back);
76603b705cfSriastradh
76703b705cfSriastradh	DamageRegionProcessPending(&front->drawable);
76803b705cfSriastradh
76903b705cfSriastradh	return new_front;
77003b705cfSriastradh}
77103b705cfSriastradh
77203b705cfSriastradhstatic void
77303b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
77403b705cfSriastradh{
77503b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv, back_priv;
77603b705cfSriastradh	int tmp;
77703b705cfSriastradh	struct intel_pixmap *new_front;
77803b705cfSriastradh
77903b705cfSriastradh	front_priv = front->driverPrivate;
78003b705cfSriastradh	back_priv = back->driverPrivate;
78103b705cfSriastradh
78203b705cfSriastradh	/* Swap BO names so DRI works */
78303b705cfSriastradh	tmp = front->name;
78403b705cfSriastradh	front->name = back->name;
78503b705cfSriastradh	back->name = tmp;
78603b705cfSriastradh
78703b705cfSriastradh	/* Swap pixmap bos */
78803b705cfSriastradh	new_front = intel_exchange_pixmap_buffers(intel,
78903b705cfSriastradh						  front_priv->pixmap,
79003b705cfSriastradh						  back_priv->pixmap);
79103b705cfSriastradh	dri_bo_unreference (intel->front_buffer);
79203b705cfSriastradh	intel->front_buffer = new_front->bo;
79303b705cfSriastradh	dri_bo_reference (intel->front_buffer);
79403b705cfSriastradh}
79503b705cfSriastradh
79603b705cfSriastradhstatic PixmapPtr
79703b705cfSriastradhintel_glamor_create_back_pixmap(ScreenPtr screen,
79803b705cfSriastradh				PixmapPtr front_pixmap,
79903b705cfSriastradh				drm_intel_bo *back_bo)
80003b705cfSriastradh{
80103b705cfSriastradh	PixmapPtr back_pixmap;
80203b705cfSriastradh
80303b705cfSriastradh	back_pixmap = screen->CreatePixmap(screen,
80403b705cfSriastradh					   0,
80503b705cfSriastradh					   0,
80603b705cfSriastradh				           front_pixmap->drawable.depth,
80703b705cfSriastradh				           0);
80803b705cfSriastradh	if (back_pixmap == NULL)
80903b705cfSriastradh		return NULL;
81003b705cfSriastradh
81103b705cfSriastradh	screen->ModifyPixmapHeader(back_pixmap,
81203b705cfSriastradh				   front_pixmap->drawable.width,
81303b705cfSriastradh				   front_pixmap->drawable.height,
81403b705cfSriastradh				   0, 0,
81503b705cfSriastradh				   front_pixmap->devKind,
81603b705cfSriastradh				   0);
81703b705cfSriastradh	intel_set_pixmap_bo(back_pixmap, back_bo);
81803b705cfSriastradh	if (!intel_glamor_create_textured_pixmap(back_pixmap)) {
81903b705cfSriastradh		ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
82003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
82103b705cfSriastradh			   "Failed to create textured back pixmap.\n");
82203b705cfSriastradh		screen->DestroyPixmap(back_pixmap);
82303b705cfSriastradh		return NULL;
82403b705cfSriastradh	}
82503b705cfSriastradh	return back_pixmap;
82603b705cfSriastradh}
82703b705cfSriastradh
82803b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
82903b705cfSriastradh{
83003b705cfSriastradh	drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
83103b705cfSriastradh	assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
83203b705cfSriastradh	return bo;
83303b705cfSriastradh}
83403b705cfSriastradh
83542542f5fSchristosstatic void
83642542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
83742542f5fSchristos{
83842542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
83942542f5fSchristos
84042542f5fSchristos        I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
84142542f5fSchristos                                 usec % 1000000,
84242542f5fSchristos                                 info);
84342542f5fSchristos}
84442542f5fSchristos
84542542f5fSchristosstatic void
84642542f5fSchristosI830DRI2FlipAbort(void *pageflip_data)
84742542f5fSchristos{
84842542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
84942542f5fSchristos
85042542f5fSchristos        i830_dri2_del_frame_event(info);
85142542f5fSchristos}
85242542f5fSchristos
85303b705cfSriastradh/*
85403b705cfSriastradh * Our internal swap routine takes care of actually exchanging, blitting, or
85503b705cfSriastradh * flipping buffers as necessary.
85603b705cfSriastradh */
85703b705cfSriastradhstatic Bool
85803b705cfSriastradhI830DRI2ScheduleFlip(struct intel_screen_private *intel,
85903b705cfSriastradh		     DrawablePtr draw,
86003b705cfSriastradh		     DRI2FrameEventPtr info)
86103b705cfSriastradh{
86203b705cfSriastradh	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
86303b705cfSriastradh	drm_intel_bo *new_back, *old_back;
86403b705cfSriastradh	int tmp_name;
86503b705cfSriastradh
86603b705cfSriastradh	if (!intel->use_triple_buffer) {
86703b705cfSriastradh		info->type = DRI2_SWAP;
86803b705cfSriastradh		if (!intel_do_pageflip(intel,
86903b705cfSriastradh				       get_pixmap_bo(priv),
87042542f5fSchristos				       info->pipe, FALSE, info,
87142542f5fSchristos                                       I830DRI2FlipComplete,
87242542f5fSchristos                                       I830DRI2FlipAbort))
87303b705cfSriastradh			return FALSE;
87403b705cfSriastradh
87503b705cfSriastradh		I830DRI2ExchangeBuffers(intel, info->front, info->back);
87603b705cfSriastradh		return TRUE;
87703b705cfSriastradh	}
87803b705cfSriastradh
87903b705cfSriastradh	if (intel->pending_flip[info->pipe]) {
88003b705cfSriastradh		assert(intel->pending_flip[info->pipe]->chain == NULL);
88103b705cfSriastradh		intel->pending_flip[info->pipe]->chain = info;
88203b705cfSriastradh		return TRUE;
88303b705cfSriastradh	}
88403b705cfSriastradh
88503b705cfSriastradh	if (intel->back_buffer == NULL) {
88642542f5fSchristos		I830DRI2BufferPrivatePtr drvpriv;
88703b705cfSriastradh		PixmapPtr front_pixmap, back_pixmap;
88803b705cfSriastradh		ScreenPtr screen;
88903b705cfSriastradh
89003b705cfSriastradh		new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
89103b705cfSriastradh					      intel->front_buffer->size, 0);
89203b705cfSriastradh		if (new_back == NULL)
89303b705cfSriastradh			return FALSE;
89403b705cfSriastradh
89503b705cfSriastradh		if (intel->front_tiling != I915_TILING_NONE) {
89603b705cfSriastradh			uint32_t tiling = intel->front_tiling;
89703b705cfSriastradh			drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
89803b705cfSriastradh			if (tiling != intel->front_tiling) {
89903b705cfSriastradh				drm_intel_bo_unreference(new_back);
90003b705cfSriastradh				return FALSE;
90103b705cfSriastradh			}
90203b705cfSriastradh		}
90303b705cfSriastradh
90403b705cfSriastradh		drm_intel_bo_disable_reuse(new_back);
90503b705cfSriastradh		dri_bo_flink(new_back, &intel->back_name);
90603b705cfSriastradh
90703b705cfSriastradh		if ((intel->uxa_flags & UXA_USE_GLAMOR)) {
90803b705cfSriastradh			screen = draw->pScreen;
90942542f5fSchristos			drvpriv = info->front->driverPrivate;
91042542f5fSchristos			front_pixmap = drvpriv->pixmap;
91103b705cfSriastradh
91203b705cfSriastradh			back_pixmap = intel_glamor_create_back_pixmap(screen,
91303b705cfSriastradh								      front_pixmap,
91403b705cfSriastradh								      new_back);
91503b705cfSriastradh			if (back_pixmap == NULL) {
91603b705cfSriastradh				drm_intel_bo_unreference(new_back);
91703b705cfSriastradh				return FALSE;
91803b705cfSriastradh			}
91903b705cfSriastradh			intel->back_pixmap = back_pixmap;
92003b705cfSriastradh		}
92103b705cfSriastradh	} else {
92203b705cfSriastradh		new_back = intel->back_buffer;
92303b705cfSriastradh		intel->back_buffer = NULL;
92403b705cfSriastradh	}
92503b705cfSriastradh
92603b705cfSriastradh	old_back = get_pixmap_bo(priv);
92742542f5fSchristos	if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
92803b705cfSriastradh		intel->back_buffer = new_back;
92903b705cfSriastradh		return FALSE;
93003b705cfSriastradh	}
93103b705cfSriastradh	info->type = DRI2_SWAP_CHAIN;
93203b705cfSriastradh	intel->pending_flip[info->pipe] = info;
93303b705cfSriastradh
93403b705cfSriastradh	priv = info->front->driverPrivate;
93503b705cfSriastradh
93603b705cfSriastradh	/* Exchange the current front-buffer with the fresh bo */
93703b705cfSriastradh
93803b705cfSriastradh	intel->back_buffer = intel->front_buffer;
93903b705cfSriastradh	drm_intel_bo_reference(intel->back_buffer);
94003b705cfSriastradh	if (!(intel->uxa_flags & UXA_USE_GLAMOR)) {
94103b705cfSriastradh		intel_set_pixmap_bo(priv->pixmap, new_back);
94203b705cfSriastradh		drm_intel_bo_unreference(new_back);
94303b705cfSriastradh	}
94403b705cfSriastradh	else
94503b705cfSriastradh		intel_exchange_pixmap_buffers(intel, priv->pixmap,
94603b705cfSriastradh					      intel->back_pixmap);
94703b705cfSriastradh
94803b705cfSriastradh	tmp_name = info->front->name;
94903b705cfSriastradh	info->front->name = intel->back_name;
95003b705cfSriastradh	intel->back_name = tmp_name;
95103b705cfSriastradh
95203b705cfSriastradh	/* Then flip DRI2 pointers and update the screen pixmap */
95303b705cfSriastradh	I830DRI2ExchangeBuffers(intel, info->front, info->back);
95403b705cfSriastradh	DRI2SwapComplete(info->client, draw, 0, 0, 0,
95503b705cfSriastradh			 DRI2_EXCHANGE_COMPLETE,
95603b705cfSriastradh			 info->event_complete,
95703b705cfSriastradh			 info->event_data);
95803b705cfSriastradh	return TRUE;
95903b705cfSriastradh}
96003b705cfSriastradh
96103b705cfSriastradhstatic Bool
96203b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
96303b705cfSriastradh{
96403b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen);
96503b705cfSriastradh	struct intel_screen_private *intel = intel_get_screen_private(pScrn);
96603b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
96703b705cfSriastradh	I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
96803b705cfSriastradh	PixmapPtr front_pixmap = front_priv->pixmap;
96903b705cfSriastradh	PixmapPtr back_pixmap = back_priv->pixmap;
97003b705cfSriastradh	struct intel_pixmap *front_intel = intel_get_pixmap_private(front_pixmap);
97103b705cfSriastradh	struct intel_pixmap *back_intel = intel_get_pixmap_private(back_pixmap);
97203b705cfSriastradh
97303b705cfSriastradh	if (!pScrn->vtSema)
97403b705cfSriastradh		return FALSE;
97503b705cfSriastradh
97642542f5fSchristos	if (I830DRI2DrawableCrtc(drawable) == NULL)
97703b705cfSriastradh		return FALSE;
97803b705cfSriastradh
97903b705cfSriastradh	if (!DRI2CanFlip(drawable))
98003b705cfSriastradh		return FALSE;
98103b705cfSriastradh
98203b705cfSriastradh	if (intel->shadow_present)
98303b705cfSriastradh		return FALSE;
98403b705cfSriastradh
98503b705cfSriastradh	if (!intel->use_pageflipping)
98603b705cfSriastradh		return FALSE;
98703b705cfSriastradh
98803b705cfSriastradh	if (front_pixmap->drawable.width != back_pixmap->drawable.width)
98903b705cfSriastradh		return FALSE;
99003b705cfSriastradh
99103b705cfSriastradh	if (front_pixmap->drawable.height != back_pixmap->drawable.height)
99203b705cfSriastradh		return FALSE;
99303b705cfSriastradh
99403b705cfSriastradh	/* XXX should we be checking depth instead of bpp? */
99503b705cfSriastradh#if 0
99603b705cfSriastradh	if (front_pixmap->drawable.depth != back_pixmap->drawable.depth)
99703b705cfSriastradh		return FALSE;
99803b705cfSriastradh#else
99903b705cfSriastradh	if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
100003b705cfSriastradh		return FALSE;
100103b705cfSriastradh#endif
100203b705cfSriastradh
100303b705cfSriastradh	/* prevent an implicit tiling mode change */
100403b705cfSriastradh	if (front_intel->tiling != back_intel->tiling)
100503b705cfSriastradh		return FALSE;
100603b705cfSriastradh
100742542f5fSchristos	if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2))
100842542f5fSchristos		return FALSE;
100942542f5fSchristos
101003b705cfSriastradh	return TRUE;
101103b705cfSriastradh}
101203b705cfSriastradh
101303b705cfSriastradhvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
101403b705cfSriastradh			       unsigned int tv_usec, DRI2FrameEventPtr swap_info)
101503b705cfSriastradh{
101603b705cfSriastradh	intel_screen_private *intel = swap_info->intel;
101703b705cfSriastradh	DrawablePtr drawable;
101803b705cfSriastradh	int status;
101903b705cfSriastradh
102003b705cfSriastradh	if (!swap_info->drawable_id)
102103b705cfSriastradh		status = BadDrawable;
102203b705cfSriastradh	else
102303b705cfSriastradh		status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
102403b705cfSriastradh					   M_ANY, DixWriteAccess);
102503b705cfSriastradh	if (status != Success) {
102642542f5fSchristos		i830_dri2_del_frame_event(swap_info);
102703b705cfSriastradh		return;
102803b705cfSriastradh	}
102903b705cfSriastradh
103003b705cfSriastradh
103103b705cfSriastradh	switch (swap_info->type) {
103203b705cfSriastradh	case DRI2_FLIP:
103303b705cfSriastradh		/* If we can still flip... */
103403b705cfSriastradh		if (can_exchange(drawable, swap_info->front, swap_info->back) &&
103503b705cfSriastradh		    I830DRI2ScheduleFlip(intel, drawable, swap_info))
103603b705cfSriastradh			return;
103703b705cfSriastradh
103803b705cfSriastradh		/* else fall through to exchange/blit */
103903b705cfSriastradh	case DRI2_SWAP: {
104003b705cfSriastradh		I830DRI2FallbackBlitSwap(drawable,
104103b705cfSriastradh					 swap_info->front, swap_info->back);
104203b705cfSriastradh		DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
104303b705cfSriastradh				 DRI2_BLIT_COMPLETE,
104403b705cfSriastradh				 swap_info->client ? swap_info->event_complete : NULL,
104503b705cfSriastradh				 swap_info->event_data);
104603b705cfSriastradh		break;
104703b705cfSriastradh	}
104803b705cfSriastradh	case DRI2_WAITMSC:
104903b705cfSriastradh		if (swap_info->client)
105003b705cfSriastradh			DRI2WaitMSCComplete(swap_info->client, drawable,
105103b705cfSriastradh					    frame, tv_sec, tv_usec);
105203b705cfSriastradh		break;
105303b705cfSriastradh	default:
105403b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
105503b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
105603b705cfSriastradh		/* Unknown type */
105703b705cfSriastradh		break;
105803b705cfSriastradh	}
105903b705cfSriastradh
106042542f5fSchristos	i830_dri2_del_frame_event(swap_info);
106103b705cfSriastradh}
106203b705cfSriastradh
106303b705cfSriastradhvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
106403b705cfSriastradh			      unsigned int tv_usec, DRI2FrameEventPtr flip_info)
106503b705cfSriastradh{
106603b705cfSriastradh	struct intel_screen_private *intel = flip_info->intel;
106703b705cfSriastradh	DrawablePtr drawable;
106803b705cfSriastradh	DRI2FrameEventPtr chain;
106903b705cfSriastradh
107003b705cfSriastradh	drawable = NULL;
107103b705cfSriastradh	if (flip_info->drawable_id)
107203b705cfSriastradh		dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
107303b705cfSriastradh				  M_ANY, DixWriteAccess);
107403b705cfSriastradh
107503b705cfSriastradh
107603b705cfSriastradh	/* We assume our flips arrive in order, so we don't check the frame */
107703b705cfSriastradh	switch (flip_info->type) {
107803b705cfSriastradh	case DRI2_SWAP:
107903b705cfSriastradh		if (!drawable)
108003b705cfSriastradh			break;
108103b705cfSriastradh
108203b705cfSriastradh		/* Check for too small vblank count of pageflip completion, taking wraparound
108303b705cfSriastradh		 * into account. This usually means some defective kms pageflip completion,
108403b705cfSriastradh		 * causing wrong (msc, ust) return values and possible visual corruption.
108503b705cfSriastradh		 */
108603b705cfSriastradh		if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
108703b705cfSriastradh			static int limit = 5;
108803b705cfSriastradh
108903b705cfSriastradh			/* XXX we are currently hitting this path with older
109003b705cfSriastradh			 * kernels, so make it quieter.
109103b705cfSriastradh			 */
109203b705cfSriastradh			if (limit) {
109303b705cfSriastradh				xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
109403b705cfSriastradh					   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
109503b705cfSriastradh					   __func__, frame, flip_info->frame);
109603b705cfSriastradh				limit--;
109703b705cfSriastradh			}
109803b705cfSriastradh
109903b705cfSriastradh			/* All-0 values signal timestamping failure. */
110003b705cfSriastradh			frame = tv_sec = tv_usec = 0;
110103b705cfSriastradh		}
110203b705cfSriastradh
110303b705cfSriastradh		DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
110403b705cfSriastradh				 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
110503b705cfSriastradh				 flip_info->event_data);
110603b705cfSriastradh		break;
110703b705cfSriastradh
110803b705cfSriastradh	case DRI2_SWAP_CHAIN:
110903b705cfSriastradh		assert(intel->pending_flip[flip_info->pipe] == flip_info);
111003b705cfSriastradh		intel->pending_flip[flip_info->pipe] = NULL;
111103b705cfSriastradh
111203b705cfSriastradh		chain = flip_info->chain;
111303b705cfSriastradh		if (chain) {
111403b705cfSriastradh			DrawablePtr chain_drawable = NULL;
111503b705cfSriastradh			if (chain->drawable_id)
111603b705cfSriastradh				 dixLookupDrawable(&chain_drawable,
111703b705cfSriastradh						   chain->drawable_id,
111803b705cfSriastradh						   serverClient,
111903b705cfSriastradh						   M_ANY, DixWriteAccess);
112003b705cfSriastradh			if (chain_drawable == NULL) {
112142542f5fSchristos				i830_dri2_del_frame_event(chain);
112203b705cfSriastradh			} else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
112303b705cfSriastradh				   !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
112403b705cfSriastradh				I830DRI2FallbackBlitSwap(chain_drawable,
112503b705cfSriastradh							 chain->front,
112603b705cfSriastradh							 chain->back);
112703b705cfSriastradh
112803b705cfSriastradh				DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
112903b705cfSriastradh						 DRI2_BLIT_COMPLETE,
113003b705cfSriastradh						 chain->client ? chain->event_complete : NULL,
113103b705cfSriastradh						 chain->event_data);
113242542f5fSchristos				i830_dri2_del_frame_event(chain);
113303b705cfSriastradh			}
113403b705cfSriastradh		}
113503b705cfSriastradh		break;
113603b705cfSriastradh
113703b705cfSriastradh	default:
113803b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
113903b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
114003b705cfSriastradh		/* Unknown type */
114103b705cfSriastradh		break;
114203b705cfSriastradh	}
114303b705cfSriastradh
114442542f5fSchristos	i830_dri2_del_frame_event(flip_info);
114503b705cfSriastradh}
114603b705cfSriastradh
114703b705cfSriastradhstatic uint32_t pipe_select(int pipe)
114803b705cfSriastradh{
114903b705cfSriastradh	if (pipe > 1)
115003b705cfSriastradh		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
115103b705cfSriastradh	else if (pipe > 0)
115203b705cfSriastradh		return DRM_VBLANK_SECONDARY;
115303b705cfSriastradh	else
115403b705cfSriastradh		return 0;
115503b705cfSriastradh}
115603b705cfSriastradh
115742542f5fSchristosstatic void
115842542f5fSchristosintel_dri2_vblank_handler(ScrnInfoPtr scrn,
115942542f5fSchristos                          xf86CrtcPtr crtc,
116042542f5fSchristos                          uint64_t msc,
116142542f5fSchristos                          uint64_t usec,
116242542f5fSchristos                          void *data)
116342542f5fSchristos{
116442542f5fSchristos        DRI2FrameEventPtr swap_info = data;
116542542f5fSchristos
116642542f5fSchristos        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
116742542f5fSchristos}
116842542f5fSchristos
116942542f5fSchristosstatic void
117042542f5fSchristosintel_dri2_vblank_abort(ScrnInfoPtr scrn,
117142542f5fSchristos                        xf86CrtcPtr crtc,
117242542f5fSchristos                        void *data)
117342542f5fSchristos{
117442542f5fSchristos        DRI2FrameEventPtr swap_info = data;
117542542f5fSchristos
117642542f5fSchristos        i830_dri2_del_frame_event(swap_info);
117742542f5fSchristos}
117842542f5fSchristos
117903b705cfSriastradh/*
118003b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the
118103b705cfSriastradh * appropriate frame.
118203b705cfSriastradh *
118303b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
118403b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap
118503b705cfSriastradh * interval for the drawable.
118603b705cfSriastradh *
118703b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap
118803b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame
118903b705cfSriastradh * immediately following the received event.
119003b705cfSriastradh *
119103b705cfSriastradh * The client will be blocked if it tries to perform further GL commands
119203b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the
119303b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if
119403b705cfSriastradh * they access buffers busy with the flip.
119503b705cfSriastradh *
119603b705cfSriastradh * When the swap is complete, the driver should call into the server so it
119703b705cfSriastradh * can send any swap complete events that have been requested.
119803b705cfSriastradh */
119903b705cfSriastradhstatic int
120003b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
120103b705cfSriastradh		     DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
120203b705cfSriastradh		     CARD64 remainder, DRI2SwapEventPtr func, void *data)
120303b705cfSriastradh{
120403b705cfSriastradh	ScreenPtr screen = draw->pScreen;
120503b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
120603b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
120703b705cfSriastradh	drmVBlank vbl;
120842542f5fSchristos	int ret;
120942542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
121042542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
121142542f5fSchristos        int flip = 0;
121203b705cfSriastradh	DRI2FrameEventPtr swap_info = NULL;
121303b705cfSriastradh	enum DRI2FrameEventType swap_type = DRI2_SWAP;
121442542f5fSchristos	uint64_t current_msc, current_ust;
121542542f5fSchristos        uint64_t request_msc;
121642542f5fSchristos        uint32_t seq;
121703b705cfSriastradh
121803b705cfSriastradh	/* Drawable not displayed... just complete the swap */
121903b705cfSriastradh	if (pipe == -1)
122003b705cfSriastradh	    goto blit_fallback;
122103b705cfSriastradh
122203b705cfSriastradh	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
122303b705cfSriastradh	if (!swap_info)
122403b705cfSriastradh	    goto blit_fallback;
122503b705cfSriastradh
122603b705cfSriastradh	swap_info->intel = intel;
122703b705cfSriastradh	swap_info->drawable_id = draw->id;
122803b705cfSriastradh	swap_info->client = client;
122903b705cfSriastradh	swap_info->event_complete = func;
123003b705cfSriastradh	swap_info->event_data = data;
123103b705cfSriastradh	swap_info->front = front;
123203b705cfSriastradh	swap_info->back = back;
123303b705cfSriastradh	swap_info->pipe = pipe;
123403b705cfSriastradh
123503b705cfSriastradh	if (!i830_dri2_add_frame_event(swap_info)) {
123603b705cfSriastradh	    free(swap_info);
123703b705cfSriastradh	    swap_info = NULL;
123803b705cfSriastradh	    goto blit_fallback;
123903b705cfSriastradh	}
124003b705cfSriastradh
124103b705cfSriastradh	I830DRI2ReferenceBuffer(front);
124203b705cfSriastradh	I830DRI2ReferenceBuffer(back);
124303b705cfSriastradh
124442542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
124542542f5fSchristos	if (ret)
124642542f5fSchristos	    goto blit_fallback;
124703b705cfSriastradh
124803b705cfSriastradh	/* Flips need to be submitted one frame before */
124903b705cfSriastradh	if (can_exchange(draw, front, back)) {
125003b705cfSriastradh	    swap_type = DRI2_FLIP;
125103b705cfSriastradh	    flip = 1;
125203b705cfSriastradh	}
125303b705cfSriastradh
125403b705cfSriastradh	swap_info->type = swap_type;
125503b705cfSriastradh
125603b705cfSriastradh	/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
125703b705cfSriastradh	 * Do it early, so handling of different timing constraints
125803b705cfSriastradh	 * for divisor, remainder and msc vs. target_msc works.
125903b705cfSriastradh	 */
126003b705cfSriastradh	if (*target_msc > 0)
126103b705cfSriastradh		*target_msc -= flip;
126203b705cfSriastradh
126303b705cfSriastradh	/*
126403b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc
126503b705cfSriastradh	 * we just need to make sure target_msc passes before initiating
126603b705cfSriastradh	 * the swap.
126703b705cfSriastradh	 */
126803b705cfSriastradh	if (divisor == 0 || current_msc < *target_msc) {
126903b705cfSriastradh		/*
127003b705cfSriastradh		 * If we can, schedule the flip directly from here rather
127103b705cfSriastradh		 * than waiting for an event from the kernel for the current
127203b705cfSriastradh		 * (or a past) MSC.
127303b705cfSriastradh		 */
127403b705cfSriastradh		if (flip && divisor == 0 && current_msc >= *target_msc &&
127503b705cfSriastradh		    I830DRI2ScheduleFlip(intel, draw, swap_info))
127603b705cfSriastradh			return TRUE;
127703b705cfSriastradh
127803b705cfSriastradh		vbl.request.type =
127903b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
128003b705cfSriastradh
128103b705cfSriastradh		/* If non-pageflipping, but blitting/exchanging, we need to use
128203b705cfSriastradh		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
128303b705cfSriastradh		 * on.
128403b705cfSriastradh		 */
128503b705cfSriastradh		if (flip == 0)
128603b705cfSriastradh			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
128703b705cfSriastradh
128803b705cfSriastradh		/* If target_msc already reached or passed, set it to
128903b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
129003b705cfSriastradh		 * to the caller. This makes swap_interval logic more robust.
129103b705cfSriastradh		 */
129203b705cfSriastradh		if (current_msc >= *target_msc)
129303b705cfSriastradh			*target_msc = current_msc;
129403b705cfSriastradh
129542542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
129642542f5fSchristos                if (!seq)
129742542f5fSchristos                        goto blit_fallback;
129842542f5fSchristos
129942542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
130042542f5fSchristos		vbl.request.signal = seq;
130142542f5fSchristos
130203b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
130303b705cfSriastradh		if (ret) {
130403b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
130503b705cfSriastradh				   "divisor 0 get vblank counter failed: %s\n",
130603b705cfSriastradh				   strerror(errno));
130703b705cfSriastradh			goto blit_fallback;
130803b705cfSriastradh		}
130903b705cfSriastradh
131042542f5fSchristos                *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
131103b705cfSriastradh		swap_info->frame = *target_msc;
131203b705cfSriastradh
131303b705cfSriastradh		return TRUE;
131403b705cfSriastradh	}
131503b705cfSriastradh
131603b705cfSriastradh	/*
131703b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
131803b705cfSriastradh	 * and we need to queue an event that will satisfy the divisor/remainder
131903b705cfSriastradh	 * equation.
132003b705cfSriastradh	 */
132103b705cfSriastradh	vbl.request.type =
132203b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
132303b705cfSriastradh	if (flip == 0)
132403b705cfSriastradh		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
132503b705cfSriastradh
132642542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
132742542f5fSchristos                remainder;
132803b705cfSriastradh
132903b705cfSriastradh	/*
133003b705cfSriastradh	 * If the calculated deadline vbl.request.sequence is smaller than
133103b705cfSriastradh	 * or equal to current_msc, it means we've passed the last point
133203b705cfSriastradh	 * when effective onset frame seq could satisfy
133303b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
133403b705cfSriastradh	 * this will happen.
133503b705cfSriastradh
133603b705cfSriastradh	 * This comparison takes the 1 frame swap delay in pageflipping mode
133703b705cfSriastradh	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
133803b705cfSriastradh	 * if we are blitting/exchanging instead of flipping.
133903b705cfSriastradh	 */
134042542f5fSchristos	if (request_msc <= current_msc)
134142542f5fSchristos		request_msc += divisor;
134242542f5fSchristos
134342542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
134442542f5fSchristos        if (!seq)
134542542f5fSchristos                goto blit_fallback;
134603b705cfSriastradh
134703b705cfSriastradh	/* Account for 1 frame extra pageflip delay if flip > 0 */
134842542f5fSchristos        vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
134942542f5fSchristos	vbl.request.signal = seq;
135003b705cfSriastradh
135103b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
135203b705cfSriastradh	if (ret) {
135303b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
135403b705cfSriastradh			   "final get vblank counter failed: %s\n",
135503b705cfSriastradh			   strerror(errno));
135603b705cfSriastradh		goto blit_fallback;
135703b705cfSriastradh	}
135803b705cfSriastradh
135903b705cfSriastradh	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
136042542f5fSchristos	*target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
136103b705cfSriastradh	swap_info->frame = *target_msc;
136203b705cfSriastradh
136303b705cfSriastradh	return TRUE;
136403b705cfSriastradh
136503b705cfSriastradhblit_fallback:
136603b705cfSriastradh	I830DRI2FallbackBlitSwap(draw, front, back);
136703b705cfSriastradh	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
136803b705cfSriastradh	if (swap_info)
136942542f5fSchristos	    i830_dri2_del_frame_event(swap_info);
137003b705cfSriastradh	*target_msc = 0; /* offscreen, so zero out target vblank count */
137103b705cfSriastradh	return TRUE;
137203b705cfSriastradh}
137303b705cfSriastradh
137403b705cfSriastradhstatic uint64_t gettime_us(void)
137503b705cfSriastradh{
137603b705cfSriastradh	struct timespec tv;
137703b705cfSriastradh
137803b705cfSriastradh	if (clock_gettime(CLOCK_MONOTONIC, &tv))
137903b705cfSriastradh		return 0;
138003b705cfSriastradh
138103b705cfSriastradh	return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
138203b705cfSriastradh}
138303b705cfSriastradh
138403b705cfSriastradh/*
138503b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's
138603b705cfSriastradh * crtc.
138703b705cfSriastradh */
138803b705cfSriastradhstatic int
138903b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
139003b705cfSriastradh{
139103b705cfSriastradh	ScreenPtr screen = draw->pScreen;
139203b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
139342542f5fSchristos	int ret;
139442542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
139503b705cfSriastradh
139603b705cfSriastradh	/* Drawable not displayed, make up a *monotonic* value */
139742542f5fSchristos	if (crtc == NULL) {
139842542f5fSchristosfail:
139903b705cfSriastradh		*ust = gettime_us();
140003b705cfSriastradh		*msc = 0;
140103b705cfSriastradh		return TRUE;
140203b705cfSriastradh	}
140303b705cfSriastradh
140442542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
140503b705cfSriastradh	if (ret) {
140603b705cfSriastradh		static int limit = 5;
140703b705cfSriastradh		if (limit) {
140803b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
140903b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
141003b705cfSriastradh				   __FUNCTION__, __LINE__,
141103b705cfSriastradh				   strerror(errno));
141203b705cfSriastradh			limit--;
141303b705cfSriastradh		}
141442542f5fSchristos		goto fail;
141503b705cfSriastradh	}
141603b705cfSriastradh
141703b705cfSriastradh	return TRUE;
141803b705cfSriastradh}
141903b705cfSriastradh
142003b705cfSriastradh/*
142103b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied.
142203b705cfSriastradh *
142303b705cfSriastradh * We need to handle the event and ask the server to wake up the client when
142403b705cfSriastradh * we receive it.
142503b705cfSriastradh */
142603b705cfSriastradhstatic int
142703b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
142803b705cfSriastradh			CARD64 divisor, CARD64 remainder)
142903b705cfSriastradh{
143003b705cfSriastradh	ScreenPtr screen = draw->pScreen;
143103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
143203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
143303b705cfSriastradh	DRI2FrameEventPtr wait_info;
143403b705cfSriastradh	drmVBlank vbl;
143542542f5fSchristos	int ret;
143642542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
143742542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
143842542f5fSchristos	CARD64 current_msc, current_ust, request_msc;
143942542f5fSchristos        uint32_t seq;
144003b705cfSriastradh
144103b705cfSriastradh	/* Drawable not visible, return immediately */
144203b705cfSriastradh	if (pipe == -1)
144303b705cfSriastradh		goto out_complete;
144403b705cfSriastradh
144503b705cfSriastradh	wait_info = calloc(1, sizeof(DRI2FrameEventRec));
144603b705cfSriastradh	if (!wait_info)
144703b705cfSriastradh		goto out_complete;
144803b705cfSriastradh
144903b705cfSriastradh	wait_info->intel = intel;
145003b705cfSriastradh	wait_info->drawable_id = draw->id;
145103b705cfSriastradh	wait_info->client = client;
145203b705cfSriastradh	wait_info->type = DRI2_WAITMSC;
145303b705cfSriastradh
145403b705cfSriastradh	if (!i830_dri2_add_frame_event(wait_info)) {
145503b705cfSriastradh	    free(wait_info);
145603b705cfSriastradh	    wait_info = NULL;
145703b705cfSriastradh	    goto out_complete;
145803b705cfSriastradh	}
145903b705cfSriastradh
146003b705cfSriastradh	/* Get current count */
146142542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
146242542f5fSchristos	if (ret)
146342542f5fSchristos	    goto out_free;
146403b705cfSriastradh
146503b705cfSriastradh	/*
146603b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc,
146703b705cfSriastradh	 * we just need to make sure target_msc passes  before waking up the
146803b705cfSriastradh	 * client.
146903b705cfSriastradh	 */
147003b705cfSriastradh	if (divisor == 0 || current_msc < target_msc) {
147103b705cfSriastradh		/* If target_msc already reached or passed, set it to
147203b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
147303b705cfSriastradh		 * to the caller. This keeps the client from continually
147403b705cfSriastradh		 * sending us MSC targets from the past by forcibly updating
147503b705cfSriastradh		 * their count on this call.
147603b705cfSriastradh		 */
147742542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
147842542f5fSchristos                if (!seq)
147942542f5fSchristos                        goto out_free;
148042542f5fSchristos
148103b705cfSriastradh		if (current_msc >= target_msc)
148203b705cfSriastradh			target_msc = current_msc;
148303b705cfSriastradh		vbl.request.type =
148403b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
148542542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
148642542f5fSchristos		vbl.request.signal = seq;
148742542f5fSchristos
148803b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
148903b705cfSriastradh		if (ret) {
149003b705cfSriastradh			static int limit = 5;
149103b705cfSriastradh			if (limit) {
149203b705cfSriastradh				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
149303b705cfSriastradh					   "%s:%d get vblank counter failed: %s\n",
149403b705cfSriastradh					   __FUNCTION__, __LINE__,
149503b705cfSriastradh					   strerror(errno));
149603b705cfSriastradh				limit--;
149703b705cfSriastradh			}
149803b705cfSriastradh			goto out_free;
149903b705cfSriastradh		}
150003b705cfSriastradh
150142542f5fSchristos		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
150203b705cfSriastradh		DRI2BlockClient(client, draw);
150303b705cfSriastradh		return TRUE;
150403b705cfSriastradh	}
150503b705cfSriastradh
150603b705cfSriastradh	/*
150703b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
150803b705cfSriastradh	 * so we queue an event that will satisfy the divisor/remainder equation.
150903b705cfSriastradh	 */
151003b705cfSriastradh	vbl.request.type =
151103b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
151203b705cfSriastradh
151342542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
151442542f5fSchristos                remainder;
151503b705cfSriastradh	/*
151603b705cfSriastradh	 * If calculated remainder is larger than requested remainder,
151703b705cfSriastradh	 * it means we've passed the last point where
151803b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
151903b705cfSriastradh	 * that will happen.
152003b705cfSriastradh	 */
152103b705cfSriastradh	if ((current_msc % divisor) >= remainder)
152242542f5fSchristos                request_msc += divisor;
152342542f5fSchristos
152442542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
152542542f5fSchristos        if (!seq)
152642542f5fSchristos                goto out_free;
152742542f5fSchristos
152842542f5fSchristos	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
152942542f5fSchristos	vbl.request.signal = seq;
153003b705cfSriastradh
153103b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
153203b705cfSriastradh	if (ret) {
153303b705cfSriastradh		static int limit = 5;
153403b705cfSriastradh		if (limit) {
153503b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
153603b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
153703b705cfSriastradh				   __FUNCTION__, __LINE__,
153803b705cfSriastradh				   strerror(errno));
153903b705cfSriastradh			limit--;
154003b705cfSriastradh		}
154103b705cfSriastradh		goto out_free;
154203b705cfSriastradh	}
154303b705cfSriastradh
154442542f5fSchristos	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
154503b705cfSriastradh	DRI2BlockClient(client, draw);
154603b705cfSriastradh
154703b705cfSriastradh	return TRUE;
154803b705cfSriastradh
154903b705cfSriastradhout_free:
155042542f5fSchristos	i830_dri2_del_frame_event(wait_info);
155103b705cfSriastradhout_complete:
155203b705cfSriastradh	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
155303b705cfSriastradh	return TRUE;
155403b705cfSriastradh}
155503b705cfSriastradh
155603b705cfSriastradhstatic int dri2_server_generation;
155703b705cfSriastradh#endif
155803b705cfSriastradh
155903b705cfSriastradhstatic int has_i830_dri(void)
156003b705cfSriastradh{
156103b705cfSriastradh	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
156203b705cfSriastradh}
156303b705cfSriastradh
156403b705cfSriastradhstatic const char *dri_driver_name(intel_screen_private *intel)
156503b705cfSriastradh{
156642542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
156703b705cfSriastradh	const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
156803b705cfSriastradh	Bool dummy;
156903b705cfSriastradh
157003b705cfSriastradh	if (s == NULL || xf86getBoolValue(&dummy, s)) {
157103b705cfSriastradh		if (INTEL_INFO(intel)->gen < 030)
157203b705cfSriastradh			return has_i830_dri() ? "i830" : "i915";
157303b705cfSriastradh		else if (INTEL_INFO(intel)->gen < 040)
157403b705cfSriastradh			return "i915";
157503b705cfSriastradh		else
157603b705cfSriastradh			return "i965";
157703b705cfSriastradh	}
157803b705cfSriastradh
157903b705cfSriastradh	return s;
158042542f5fSchristos#else
158142542f5fSchristos	if (INTEL_INFO(intel)->gen < 030)
158242542f5fSchristos		return has_i830_dri() ? "i830" : "i915";
158342542f5fSchristos	else if (INTEL_INFO(intel)->gen < 040)
158442542f5fSchristos		return "i915";
158542542f5fSchristos	else
158642542f5fSchristos		return "i965";
158742542f5fSchristos#endif
158803b705cfSriastradh}
158903b705cfSriastradh
159003b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen)
159103b705cfSriastradh{
159203b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
159303b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
159403b705cfSriastradh	DRI2InfoRec info;
159542542f5fSchristos	int dri2scr_major = 1;
159642542f5fSchristos	int dri2scr_minor = 0;
159703b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
159842542f5fSchristos	const char *driverNames[2];
159903b705cfSriastradh#endif
160003b705cfSriastradh
160103b705cfSriastradh	if (intel->force_fallback) {
160203b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
160303b705cfSriastradh			   "cannot enable DRI2 whilst forcing software fallbacks\n");
160403b705cfSriastradh		return FALSE;
160503b705cfSriastradh	}
160603b705cfSriastradh
160703b705cfSriastradh	if (xf86LoaderCheckSymbol("DRI2Version"))
160842542f5fSchristos		DRI2Version(&dri2scr_major, &dri2scr_minor);
160903b705cfSriastradh
161042542f5fSchristos	if (dri2scr_minor < 1) {
161103b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
161203b705cfSriastradh			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
161303b705cfSriastradh		return FALSE;
161403b705cfSriastradh	}
161503b705cfSriastradh
161603b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
161703b705cfSriastradh	if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID)))
161803b705cfSriastradh		return FALSE;
161903b705cfSriastradh#else
162003b705cfSriastradh	if (!dixRequestPrivate(&i830_client_key, sizeof(XID)))
162103b705cfSriastradh		return FALSE;
162203b705cfSriastradh#endif
162303b705cfSriastradh
162403b705cfSriastradh
162503b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
162603b705cfSriastradh	if (serverGeneration != dri2_server_generation) {
162703b705cfSriastradh	    dri2_server_generation = serverGeneration;
162803b705cfSriastradh	    if (!i830_dri2_register_frame_event_resource_types()) {
162903b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
163003b705cfSriastradh			   "Cannot register DRI2 frame event resources\n");
163103b705cfSriastradh		return FALSE;
163203b705cfSriastradh	    }
163303b705cfSriastradh	}
163403b705cfSriastradh#endif
163503b705cfSriastradh
163603b705cfSriastradh	intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD);
163703b705cfSriastradh	memset(&info, '\0', sizeof(info));
163803b705cfSriastradh	info.fd = intel->drmSubFD;
163903b705cfSriastradh	info.driverName = dri_driver_name(intel);
164003b705cfSriastradh	info.deviceName = intel->deviceName;
164103b705cfSriastradh
164203b705cfSriastradh#if DRI2INFOREC_VERSION == 1
164303b705cfSriastradh	info.version = 1;
164403b705cfSriastradh	info.CreateBuffers = I830DRI2CreateBuffers;
164503b705cfSriastradh	info.DestroyBuffers = I830DRI2DestroyBuffers;
164603b705cfSriastradh#elif DRI2INFOREC_VERSION == 2
164703b705cfSriastradh	/* The ABI between 2 and 3 was broken so we could get rid of
164803b705cfSriastradh	 * the multi-buffer alloc functions.  Make sure we indicate the
164903b705cfSriastradh	 * right version so DRI2 can reject us if it's version 3 or above. */
165003b705cfSriastradh	info.version = 2;
165103b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
165203b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
165303b705cfSriastradh#else
165403b705cfSriastradh	info.version = 3;
165503b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
165603b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
165703b705cfSriastradh#endif
165803b705cfSriastradh
165903b705cfSriastradh	info.CopyRegion = I830DRI2CopyRegion;
166003b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
166103b705cfSriastradh	info.version = 4;
166203b705cfSriastradh	info.ScheduleSwap = I830DRI2ScheduleSwap;
166303b705cfSriastradh	info.GetMSC = I830DRI2GetMSC;
166403b705cfSriastradh	info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
166542542f5fSchristos	info.numDrivers = 2;
166603b705cfSriastradh	info.driverNames = driverNames;
166703b705cfSriastradh	driverNames[0] = info.driverName;
166842542f5fSchristos	driverNames[1] = info.driverName;
166903b705cfSriastradh#endif
167003b705cfSriastradh
167103b705cfSriastradh	return DRI2ScreenInit(screen, &info);
167203b705cfSriastradh}
167303b705cfSriastradh
167403b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen)
167503b705cfSriastradh{
167603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
167703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
167803b705cfSriastradh
167903b705cfSriastradh	DRI2CloseScreen(screen);
168003b705cfSriastradh	drmFree(intel->deviceName);
168103b705cfSriastradh}
1682