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
84fe8aea9eSmrgstatic void I830DRI2FlipEventHandler(unsigned int frame,
85fe8aea9eSmrg				     unsigned int tv_sec,
86fe8aea9eSmrg				     unsigned int tv_usec,
87fe8aea9eSmrg				     DRI2FrameEventPtr flip_info);
88fe8aea9eSmrg
89fe8aea9eSmrgstatic void I830DRI2FrameEventHandler(unsigned int frame,
90fe8aea9eSmrg				      unsigned int tv_sec,
91fe8aea9eSmrg				      unsigned int tv_usec,
92fe8aea9eSmrg				      DRI2FrameEventPtr swap_info);
93fe8aea9eSmrg
94fe8aea9eSmrgstatic void
95fe8aea9eSmrgi830_dri2_del_frame_event(DRI2FrameEventPtr info);
96fe8aea9eSmrg
97fe8aea9eSmrgstatic uint32_t pipe_select(int pipe)
98fe8aea9eSmrg{
99fe8aea9eSmrg	if (pipe > 1)
100fe8aea9eSmrg		return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
101fe8aea9eSmrg	else if (pipe > 0)
102fe8aea9eSmrg		return DRM_VBLANK_SECONDARY;
103fe8aea9eSmrg	else
104fe8aea9eSmrg		return 0;
105fe8aea9eSmrg}
106fe8aea9eSmrg
107fe8aea9eSmrgstatic void
108fe8aea9eSmrgintel_dri2_vblank_handler(ScrnInfoPtr scrn,
109fe8aea9eSmrg                          xf86CrtcPtr crtc,
110fe8aea9eSmrg                          uint64_t msc,
111fe8aea9eSmrg                          uint64_t usec,
112fe8aea9eSmrg                          void *data)
113fe8aea9eSmrg{
114fe8aea9eSmrg        I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data);
115fe8aea9eSmrg}
116fe8aea9eSmrg
117fe8aea9eSmrgstatic void
118fe8aea9eSmrgintel_dri2_vblank_abort(ScrnInfoPtr scrn,
119fe8aea9eSmrg                        xf86CrtcPtr crtc,
120fe8aea9eSmrg                        void *data)
121fe8aea9eSmrg{
122fe8aea9eSmrg        i830_dri2_del_frame_event(data);
123fe8aea9eSmrg}
124fe8aea9eSmrg
12503b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap)
12603b705cfSriastradh{
12713496ba1Ssnj	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
12803b705cfSriastradh	uint32_t name;
12903b705cfSriastradh
13003b705cfSriastradh	if (priv == NULL || priv->bo == NULL)
13103b705cfSriastradh		return 0;
13203b705cfSriastradh
13303b705cfSriastradh	if (dri_bo_flink(priv->bo, &name) != 0)
13403b705cfSriastradh		return 0;
13503b705cfSriastradh
13642542f5fSchristos	priv->pinned |= PIN_DRI2;
13703b705cfSriastradh	return name;
13803b705cfSriastradh}
13903b705cfSriastradh
14003b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable)
14103b705cfSriastradh{
14203b705cfSriastradh	PixmapPtr pixmap;
14303b705cfSriastradh
14403b705cfSriastradh	pixmap = get_drawable_pixmap(drawable);
14503b705cfSriastradh	if (!intel_get_pixmap_bo(pixmap))
14603b705cfSriastradh		return NULL;
14703b705cfSriastradh
14803b705cfSriastradh	pixmap->refcnt++;
14903b705cfSriastradh	return pixmap;
15003b705cfSriastradh}
15103b705cfSriastradh
15203b705cfSriastradh#if DRI2INFOREC_VERSION < 2
15303b705cfSriastradhstatic DRI2BufferPtr
15403b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
15503b705cfSriastradh		      int count)
15603b705cfSriastradh{
15703b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
15803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
15903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
16003b705cfSriastradh	DRI2BufferPtr buffers;
16103b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
16203b705cfSriastradh	PixmapPtr pixmap, pDepthPixmap;
16303b705cfSriastradh	int i;
16403b705cfSriastradh
16503b705cfSriastradh	buffers = calloc(count, sizeof *buffers);
16603b705cfSriastradh	if (buffers == NULL)
16703b705cfSriastradh		return NULL;
16803b705cfSriastradh	privates = calloc(count, sizeof *privates);
16903b705cfSriastradh	if (privates == NULL) {
17003b705cfSriastradh		free(buffers);
17103b705cfSriastradh		return NULL;
17203b705cfSriastradh	}
17303b705cfSriastradh
17403b705cfSriastradh	pDepthPixmap = NULL;
17503b705cfSriastradh	for (i = 0; i < count; i++) {
17603b705cfSriastradh		pixmap = NULL;
17703b705cfSriastradh		if (attachments[i] == DRI2BufferFrontLeft) {
17803b705cfSriastradh			pixmap = get_front_buffer(drawable);
17903b705cfSriastradh		} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
18003b705cfSriastradh			pixmap = pDepthPixmap;
18103b705cfSriastradh			pixmap->refcnt++;
18203b705cfSriastradh		}
18303b705cfSriastradh
18403b705cfSriastradh		if (pixmap == NULL) {
18503b705cfSriastradh			unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
18603b705cfSriastradh
18703b705cfSriastradh			if (intel->tiling & INTEL_TILING_3D) {
18803b705cfSriastradh				switch (attachments[i]) {
18903b705cfSriastradh				case DRI2BufferDepth:
19003b705cfSriastradh					if (SUPPORTS_YTILING(intel))
19103b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_Y;
19203b705cfSriastradh					else
19303b705cfSriastradh						hint |= INTEL_CREATE_PIXMAP_TILING_X;
19403b705cfSriastradh					break;
19503b705cfSriastradh				case DRI2BufferFakeFrontLeft:
19603b705cfSriastradh				case DRI2BufferFakeFrontRight:
19703b705cfSriastradh				case DRI2BufferBackLeft:
19803b705cfSriastradh				case DRI2BufferBackRight:
19903b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_X;
20003b705cfSriastradh					break;
20103b705cfSriastradh				}
20203b705cfSriastradh			}
20303b705cfSriastradh
20403b705cfSriastradh			pixmap = screen->CreatePixmap(screen,
20503b705cfSriastradh						      drawable->width,
20603b705cfSriastradh						      drawable->height,
20703b705cfSriastradh						      drawable->depth,
20803b705cfSriastradh						      hint);
20903b705cfSriastradh			if (pixmap == NULL ||
21003b705cfSriastradh			    intel_get_pixmap_bo(pixmap) == NULL)
21103b705cfSriastradh			{
21203b705cfSriastradh				if (pixmap)
21303b705cfSriastradh					screen->DestroyPixmap(pixmap);
21403b705cfSriastradh				goto unwind;
21503b705cfSriastradh			}
21603b705cfSriastradh		}
21703b705cfSriastradh
21803b705cfSriastradh		if (attachments[i] == DRI2BufferDepth)
21903b705cfSriastradh			pDepthPixmap = pixmap;
22003b705cfSriastradh
22103b705cfSriastradh		buffers[i].attachment = attachments[i];
22203b705cfSriastradh		buffers[i].pitch = pixmap->devKind;
22303b705cfSriastradh		buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
22403b705cfSriastradh		buffers[i].driverPrivate = &privates[i];
22503b705cfSriastradh		buffers[i].flags = 0;	/* not tiled */
22603b705cfSriastradh		privates[i].refcnt = 1;
22703b705cfSriastradh		privates[i].pixmap = pixmap;
22803b705cfSriastradh
22903b705cfSriastradh		if ((buffers[i].name = pixmap_flink(pixmap)) == 0) {
23003b705cfSriastradh			/* failed to name buffer */
23103b705cfSriastradh			screen->DestroyPixmap(pixmap);
23203b705cfSriastradh			goto unwind;
23303b705cfSriastradh		}
23403b705cfSriastradh	}
23503b705cfSriastradh
23603b705cfSriastradh	return buffers;
23703b705cfSriastradh
23803b705cfSriastradhunwind:
23903b705cfSriastradh	while (i--)
24003b705cfSriastradh		screen->DestroyPixmap(privates[i].pixmap);
24103b705cfSriastradh	free(privates);
24203b705cfSriastradh	free(buffers);
24303b705cfSriastradh	return NULL;
24403b705cfSriastradh}
24503b705cfSriastradh
24603b705cfSriastradhstatic void
24703b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count)
24803b705cfSriastradh{
24903b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
25003b705cfSriastradh	I830DRI2BufferPrivatePtr private;
25103b705cfSriastradh	int i;
25203b705cfSriastradh
25303b705cfSriastradh	for (i = 0; i < count; i++) {
25403b705cfSriastradh		private = buffers[i].driverPrivate;
25503b705cfSriastradh		screen->DestroyPixmap(private->pixmap);
25603b705cfSriastradh	}
25703b705cfSriastradh
25803b705cfSriastradh	if (buffers) {
25903b705cfSriastradh		free(buffers[0].driverPrivate);
26003b705cfSriastradh		free(buffers);
26103b705cfSriastradh	}
26203b705cfSriastradh}
26303b705cfSriastradh
26403b705cfSriastradh#else
26503b705cfSriastradh
26603b705cfSriastradhstatic DRI2Buffer2Ptr
26703b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
26803b705cfSriastradh		     unsigned int format)
26903b705cfSriastradh{
27003b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
27103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
27203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
27303b705cfSriastradh	DRI2Buffer2Ptr buffer;
27403b705cfSriastradh	I830DRI2BufferPrivatePtr privates;
27503b705cfSriastradh	PixmapPtr pixmap;
27603b705cfSriastradh
27703b705cfSriastradh	buffer = calloc(1, sizeof *buffer);
27803b705cfSriastradh	if (buffer == NULL)
27903b705cfSriastradh		return NULL;
28003b705cfSriastradh	privates = calloc(1, sizeof *privates);
28103b705cfSriastradh	if (privates == NULL) {
28203b705cfSriastradh		free(buffer);
28303b705cfSriastradh		return NULL;
28403b705cfSriastradh	}
28503b705cfSriastradh
28603b705cfSriastradh	pixmap = NULL;
287fe8aea9eSmrg	if (attachment == DRI2BufferFrontLeft)
28803b705cfSriastradh		pixmap = get_front_buffer(drawable);
28903b705cfSriastradh
29003b705cfSriastradh	if (pixmap == NULL) {
29103b705cfSriastradh		unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
29203b705cfSriastradh		int pixmap_width = drawable->width;
29303b705cfSriastradh		int pixmap_height = drawable->height;
29403b705cfSriastradh		int pixmap_cpp = (format != 0) ? format : drawable->depth;
29503b705cfSriastradh
29603b705cfSriastradh		if (intel->tiling & INTEL_TILING_3D) {
29703b705cfSriastradh			switch (attachment) {
29803b705cfSriastradh			case DRI2BufferDepth:
29903b705cfSriastradh			case DRI2BufferDepthStencil:
30003b705cfSriastradh			case DRI2BufferHiz:
30103b705cfSriastradh				if (SUPPORTS_YTILING(intel)) {
30203b705cfSriastradh					hint |= INTEL_CREATE_PIXMAP_TILING_Y;
30303b705cfSriastradh					break;
30403b705cfSriastradh				}
30503b705cfSriastradh			case DRI2BufferAccum:
30603b705cfSriastradh			case DRI2BufferBackLeft:
30703b705cfSriastradh			case DRI2BufferBackRight:
30803b705cfSriastradh			case DRI2BufferFakeFrontLeft:
30903b705cfSriastradh			case DRI2BufferFakeFrontRight:
31003b705cfSriastradh			case DRI2BufferFrontLeft:
31103b705cfSriastradh			case DRI2BufferFrontRight:
31203b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_X;
31303b705cfSriastradh				break;
31403b705cfSriastradh			case DRI2BufferStencil:
31503b705cfSriastradh				/*
31603b705cfSriastradh				 * The stencil buffer is W tiled. However, we
31703b705cfSriastradh				 * request from the kernel a non-tiled buffer
31803b705cfSriastradh				 * because the GTT is incapable of W fencing.
31903b705cfSriastradh				 */
32003b705cfSriastradh				hint |= INTEL_CREATE_PIXMAP_TILING_NONE;
32103b705cfSriastradh				break;
32203b705cfSriastradh			default:
32303b705cfSriastradh				free(privates);
32403b705cfSriastradh				free(buffer);
32503b705cfSriastradh				return NULL;
32603b705cfSriastradh                        }
32703b705cfSriastradh		}
32803b705cfSriastradh
32903b705cfSriastradh		/*
33003b705cfSriastradh		 * The stencil buffer has quirky pitch requirements.  From Vol
33103b705cfSriastradh		 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface
33203b705cfSriastradh		 * Pitch":
33303b705cfSriastradh		 *    The pitch must be set to 2x the value computed based on
33403b705cfSriastradh		 *    width, as the stencil buffer is stored with two rows
33503b705cfSriastradh		 *    interleaved.
33603b705cfSriastradh		 * To accomplish this, we resort to the nasty hack of doubling
33703b705cfSriastradh		 * the drm region's cpp and halving its height.
33803b705cfSriastradh		 *
33903b705cfSriastradh		 * If we neglect to double the pitch, then render corruption
34003b705cfSriastradh		 * occurs.
34103b705cfSriastradh		 */
34203b705cfSriastradh		if (attachment == DRI2BufferStencil) {
34303b705cfSriastradh			pixmap_width = ALIGN(pixmap_width, 64);
34403b705cfSriastradh			pixmap_height = ALIGN((pixmap_height + 1) / 2, 64);
34503b705cfSriastradh			pixmap_cpp *= 2;
34603b705cfSriastradh		}
34703b705cfSriastradh
34803b705cfSriastradh		pixmap = screen->CreatePixmap(screen,
34903b705cfSriastradh					      pixmap_width,
35003b705cfSriastradh					      pixmap_height,
35103b705cfSriastradh					      pixmap_cpp,
35203b705cfSriastradh					      hint);
35303b705cfSriastradh		if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) {
35403b705cfSriastradh			if (pixmap)
35503b705cfSriastradh				screen->DestroyPixmap(pixmap);
35603b705cfSriastradh			free(privates);
35703b705cfSriastradh			free(buffer);
35803b705cfSriastradh			return NULL;
35903b705cfSriastradh		}
36003b705cfSriastradh	}
36103b705cfSriastradh
36203b705cfSriastradh	buffer->attachment = attachment;
36303b705cfSriastradh	buffer->pitch = pixmap->devKind;
36403b705cfSriastradh	buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
36503b705cfSriastradh	buffer->driverPrivate = privates;
36603b705cfSriastradh	buffer->format = format;
36703b705cfSriastradh	buffer->flags = 0;	/* not tiled */
36803b705cfSriastradh	privates->refcnt = 1;
36903b705cfSriastradh	privates->pixmap = pixmap;
37003b705cfSriastradh
37103b705cfSriastradh	if ((buffer->name = pixmap_flink(pixmap)) == 0) {
37203b705cfSriastradh		/* failed to name buffer */
37303b705cfSriastradh		screen->DestroyPixmap(pixmap);
37403b705cfSriastradh		free(privates);
37503b705cfSriastradh		free(buffer);
37603b705cfSriastradh		return NULL;
37703b705cfSriastradh	}
37803b705cfSriastradh
37903b705cfSriastradh	return buffer;
38003b705cfSriastradh}
38103b705cfSriastradh
38203b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
38303b705cfSriastradh{
38403b705cfSriastradh	if (buffer && buffer->driverPrivate) {
38503b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
38603b705cfSriastradh		if (--private->refcnt == 0) {
38703b705cfSriastradh			ScreenPtr screen = private->pixmap->drawable.pScreen;
38803b705cfSriastradh			screen->DestroyPixmap(private->pixmap);
38903b705cfSriastradh
39003b705cfSriastradh			free(private);
39103b705cfSriastradh			free(buffer);
39203b705cfSriastradh		}
39303b705cfSriastradh	} else
39403b705cfSriastradh		free(buffer);
39503b705cfSriastradh}
39603b705cfSriastradh
39703b705cfSriastradh#endif
39803b705cfSriastradh
39903b705cfSriastradhstatic void
40003b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
40103b705cfSriastradh		   DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
40203b705cfSriastradh{
40303b705cfSriastradh	I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate;
40403b705cfSriastradh	I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate;
40503b705cfSriastradh	ScreenPtr screen = drawable->pScreen;
40603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
40703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
40803b705cfSriastradh	DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft)
40903b705cfSriastradh		? drawable : &srcPrivate->pixmap->drawable;
41003b705cfSriastradh	DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft)
41103b705cfSriastradh		? drawable : &dstPrivate->pixmap->drawable;
41203b705cfSriastradh	RegionPtr pCopyClip;
41303b705cfSriastradh	GCPtr gc;
41403b705cfSriastradh
41503b705cfSriastradh	gc = GetScratchGC(dst->depth, screen);
41603b705cfSriastradh	if (!gc)
41703b705cfSriastradh		return;
41803b705cfSriastradh
41903b705cfSriastradh	pCopyClip = REGION_CREATE(screen, NULL, 0);
42003b705cfSriastradh	REGION_COPY(screen, pCopyClip, pRegion);
42103b705cfSriastradh	(*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0);
42203b705cfSriastradh	ValidateGC(dst, gc);
42303b705cfSriastradh
42403b705cfSriastradh	/* Wait for the scanline to be outside the region to be copied */
42503b705cfSriastradh	if (scrn->vtSema &&
42603b705cfSriastradh	    pixmap_is_scanout(get_drawable_pixmap(dst)) &&
42703b705cfSriastradh	    intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) {
42803b705cfSriastradh		BoxPtr box;
42903b705cfSriastradh		BoxRec crtcbox;
43003b705cfSriastradh		int y1, y2;
43103b705cfSriastradh		int event, load_scan_lines_pipe;
43203b705cfSriastradh		xf86CrtcPtr crtc;
43303b705cfSriastradh		Bool full_height = FALSE;
43403b705cfSriastradh
43503b705cfSriastradh		box = REGION_EXTENTS(unused, gc->pCompositeClip);
43603b705cfSriastradh		crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox);
43703b705cfSriastradh
43803b705cfSriastradh		/*
43903b705cfSriastradh		 * Make sure the CRTC is valid and this is the real front
44003b705cfSriastradh		 * buffer
44103b705cfSriastradh		 */
44203b705cfSriastradh		if (crtc != NULL && !crtc->rotatedData) {
44303b705cfSriastradh			int pipe = intel_crtc_to_pipe(crtc);
44403b705cfSriastradh
44503b705cfSriastradh			/*
44603b705cfSriastradh			 * Make sure we don't wait for a scanline that will
44703b705cfSriastradh			 * never occur
44803b705cfSriastradh			 */
44903b705cfSriastradh			y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
45003b705cfSriastradh			y2 = (box->y2 <= crtcbox.y2) ?
45103b705cfSriastradh			    box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
45203b705cfSriastradh
45303b705cfSriastradh			if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1))
45403b705cfSriastradh			    full_height = TRUE;
45503b705cfSriastradh
45603b705cfSriastradh			/*
45703b705cfSriastradh			 * Pre-965 doesn't have SVBLANK, so we need a bit
45803b705cfSriastradh			 * of extra time for the blitter to start up and
45903b705cfSriastradh			 * do its job for a full height blit
46003b705cfSriastradh			 */
46103b705cfSriastradh			if (full_height && INTEL_INFO(intel)->gen < 040)
46203b705cfSriastradh			    y2 -= 2;
46303b705cfSriastradh
46403b705cfSriastradh			if (pipe == 0) {
46503b705cfSriastradh				event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
46603b705cfSriastradh				load_scan_lines_pipe =
46703b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
46803b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
46903b705cfSriastradh				    event = MI_WAIT_FOR_PIPEA_SVBLANK;
47003b705cfSriastradh			} else {
47103b705cfSriastradh				event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
47203b705cfSriastradh				load_scan_lines_pipe =
47303b705cfSriastradh				    MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
47403b705cfSriastradh				if (full_height && INTEL_INFO(intel)->gen >= 040)
47503b705cfSriastradh				    event = MI_WAIT_FOR_PIPEB_SVBLANK;
47603b705cfSriastradh			}
47703b705cfSriastradh
47803b705cfSriastradh			if (crtc->mode.Flags & V_INTERLACE) {
47903b705cfSriastradh				/* DSL count field lines */
48003b705cfSriastradh				y1 /= 2;
48103b705cfSriastradh				y2 /= 2;
48203b705cfSriastradh			}
48303b705cfSriastradh
48403b705cfSriastradh			BEGIN_BATCH(5);
48503b705cfSriastradh			/*
48603b705cfSriastradh			 * The documentation says that the LOAD_SCAN_LINES
48703b705cfSriastradh			 * command always comes in pairs. Don't ask me why.
48803b705cfSriastradh			 */
48903b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
49003b705cfSriastradh				  load_scan_lines_pipe);
49103b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
49203b705cfSriastradh			OUT_BATCH(MI_LOAD_SCAN_LINES_INCL |
49303b705cfSriastradh				  load_scan_lines_pipe);
49403b705cfSriastradh			OUT_BATCH((y1 << 16) | (y2-1));
49503b705cfSriastradh			OUT_BATCH(MI_WAIT_FOR_EVENT | event);
49603b705cfSriastradh			ADVANCE_BATCH();
49703b705cfSriastradh		}
49803b705cfSriastradh	}
49903b705cfSriastradh
50003b705cfSriastradh	/* It's important that this copy gets submitted before the
50103b705cfSriastradh	 * direct rendering client submits rendering for the next
50203b705cfSriastradh	 * frame, but we don't actually need to submit right now.  The
50303b705cfSriastradh	 * client will wait for the DRI2CopyRegion reply or the swap
50403b705cfSriastradh	 * buffer event before rendering, and we'll hit the flush
50503b705cfSriastradh	 * callback chain before those messages are sent.  We submit
50603b705cfSriastradh	 * our batch buffers from the flush callback chain so we know
50703b705cfSriastradh	 * that will happen before the client tries to render
50803b705cfSriastradh	 * again. */
50903b705cfSriastradh
51003b705cfSriastradh	gc->ops->CopyArea(src, dst, gc,
51103b705cfSriastradh			  0, 0,
51203b705cfSriastradh			  drawable->width, drawable->height,
51303b705cfSriastradh			  0, 0);
51403b705cfSriastradh
51503b705cfSriastradh	FreeScratchGC(gc);
51603b705cfSriastradh
51703b705cfSriastradh	/* And make sure the WAIT_FOR_EVENT is queued before any
51803b705cfSriastradh	 * modesetting/dpms operations on the pipe.
51903b705cfSriastradh	 */
52003b705cfSriastradh	intel_batch_submit(scrn);
52103b705cfSriastradh}
52203b705cfSriastradh
52303b705cfSriastradhstatic void
52403b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable,
52503b705cfSriastradh			 DRI2BufferPtr dst,
52603b705cfSriastradh			 DRI2BufferPtr src)
52703b705cfSriastradh{
52803b705cfSriastradh	BoxRec box;
52903b705cfSriastradh	RegionRec region;
53003b705cfSriastradh
53103b705cfSriastradh	box.x1 = 0;
53203b705cfSriastradh	box.y1 = 0;
53303b705cfSriastradh	box.x2 = drawable->width;
53403b705cfSriastradh	box.y2 = drawable->height;
53503b705cfSriastradh	REGION_INIT(pScreen, &region, &box, 0);
53603b705cfSriastradh
53703b705cfSriastradh	I830DRI2CopyRegion(drawable, &region, dst, src);
53803b705cfSriastradh}
53903b705cfSriastradh
54003b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
54103b705cfSriastradh
54203b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
54303b705cfSriastradh{
54403b705cfSriastradh	if (buffer) {
54503b705cfSriastradh		I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
54603b705cfSriastradh		private->refcnt++;
54703b705cfSriastradh	}
54803b705cfSriastradh}
54903b705cfSriastradh
55042542f5fSchristosstatic xf86CrtcPtr
55142542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw)
55203b705cfSriastradh{
55303b705cfSriastradh	ScreenPtr pScreen = pDraw->pScreen;
55403b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
55503b705cfSriastradh	BoxRec box, crtcbox;
55642542f5fSchristos	xf86CrtcPtr crtc = NULL;
55703b705cfSriastradh
55803b705cfSriastradh	box.x1 = pDraw->x;
55903b705cfSriastradh	box.y1 = pDraw->y;
56003b705cfSriastradh	box.x2 = box.x1 + pDraw->width;
56103b705cfSriastradh	box.y2 = box.y1 + pDraw->height;
56203b705cfSriastradh
56342542f5fSchristos	if (pDraw->type != DRAWABLE_PIXMAP)
56442542f5fSchristos		crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox);
56503b705cfSriastradh
56603b705cfSriastradh	/* Make sure the CRTC is valid and this is the real front buffer */
56703b705cfSriastradh	if (crtc != NULL && !crtc->rotatedData)
56842542f5fSchristos                return crtc;
56903b705cfSriastradh
57042542f5fSchristos	return NULL;
57103b705cfSriastradh}
57203b705cfSriastradh
57303b705cfSriastradhstatic RESTYPE	frame_event_client_type, frame_event_drawable_type;
57403b705cfSriastradh
57503b705cfSriastradhstruct i830_dri2_resource {
57603b705cfSriastradh	XID id;
57703b705cfSriastradh	RESTYPE type;
57803b705cfSriastradh	struct list list;
57903b705cfSriastradh};
58003b705cfSriastradh
58103b705cfSriastradhstatic struct i830_dri2_resource *
58203b705cfSriastradhget_resource(XID id, RESTYPE type)
58303b705cfSriastradh{
58403b705cfSriastradh	struct i830_dri2_resource *resource;
58503b705cfSriastradh	void *ptr;
58603b705cfSriastradh
58703b705cfSriastradh	ptr = NULL;
58803b705cfSriastradh	dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
58903b705cfSriastradh	if (ptr)
59003b705cfSriastradh		return ptr;
59103b705cfSriastradh
59203b705cfSriastradh	resource = malloc(sizeof(*resource));
59303b705cfSriastradh	if (resource == NULL)
59403b705cfSriastradh		return NULL;
59503b705cfSriastradh
59603b705cfSriastradh	if (!AddResource(id, type, resource)) {
59703b705cfSriastradh		free(resource);
59803b705cfSriastradh		return NULL;
59903b705cfSriastradh	}
60003b705cfSriastradh
60103b705cfSriastradh	resource->id = id;
60203b705cfSriastradh	resource->type = type;
60303b705cfSriastradh	list_init(&resource->list);
60403b705cfSriastradh	return resource;
60503b705cfSriastradh}
60603b705cfSriastradh
60703b705cfSriastradhstatic int
60803b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id)
60903b705cfSriastradh{
61003b705cfSriastradh	struct i830_dri2_resource *resource = data;
61103b705cfSriastradh
61203b705cfSriastradh	while (!list_is_empty(&resource->list)) {
61303b705cfSriastradh		DRI2FrameEventPtr info =
61403b705cfSriastradh			list_first_entry(&resource->list,
61503b705cfSriastradh					 DRI2FrameEventRec,
61603b705cfSriastradh					 client_resource);
61703b705cfSriastradh
61803b705cfSriastradh		list_del(&info->client_resource);
61903b705cfSriastradh		info->client = NULL;
62003b705cfSriastradh	}
62103b705cfSriastradh	free(resource);
62203b705cfSriastradh
62303b705cfSriastradh	return Success;
62403b705cfSriastradh}
62503b705cfSriastradh
62603b705cfSriastradhstatic int
62703b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id)
62803b705cfSriastradh{
62903b705cfSriastradh	struct i830_dri2_resource *resource = data;
63003b705cfSriastradh
63103b705cfSriastradh	while (!list_is_empty(&resource->list)) {
63203b705cfSriastradh		DRI2FrameEventPtr info =
63303b705cfSriastradh			list_first_entry(&resource->list,
63403b705cfSriastradh					 DRI2FrameEventRec,
63503b705cfSriastradh					 drawable_resource);
63603b705cfSriastradh
63703b705cfSriastradh		list_del(&info->drawable_resource);
63803b705cfSriastradh		info->drawable_id = None;
63903b705cfSriastradh	}
64003b705cfSriastradh	free(resource);
64103b705cfSriastradh
64203b705cfSriastradh	return Success;
64303b705cfSriastradh}
64403b705cfSriastradh
64503b705cfSriastradhstatic Bool
64603b705cfSriastradhi830_dri2_register_frame_event_resource_types(void)
64703b705cfSriastradh{
64803b705cfSriastradh	frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client");
64903b705cfSriastradh	if (!frame_event_client_type)
65003b705cfSriastradh		return FALSE;
65103b705cfSriastradh
65203b705cfSriastradh	frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable");
65303b705cfSriastradh	if (!frame_event_drawable_type)
65403b705cfSriastradh		return FALSE;
65503b705cfSriastradh
65603b705cfSriastradh	return TRUE;
65703b705cfSriastradh}
65803b705cfSriastradh
65903b705cfSriastradhstatic XID
66003b705cfSriastradhget_client_id(ClientPtr client)
66103b705cfSriastradh{
66203b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
66303b705cfSriastradh	XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key);
66403b705cfSriastradh#else
66503b705cfSriastradh	XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key);
66603b705cfSriastradh#endif
66703b705cfSriastradh	if (*ptr == 0)
66803b705cfSriastradh		*ptr = FakeClientID(client->index);
66903b705cfSriastradh	return *ptr;
67003b705cfSriastradh}
67103b705cfSriastradh
67203b705cfSriastradh/*
67303b705cfSriastradh * Hook this frame event into the server resource
67403b705cfSriastradh * database so we can clean it up if the drawable or
67503b705cfSriastradh * client exits while the swap is pending
67603b705cfSriastradh */
67703b705cfSriastradhstatic Bool
67803b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info)
67903b705cfSriastradh{
68003b705cfSriastradh	struct i830_dri2_resource *resource;
68103b705cfSriastradh
68203b705cfSriastradh	resource = get_resource(get_client_id(info->client),
68303b705cfSriastradh				frame_event_client_type);
68403b705cfSriastradh	if (resource == NULL)
68503b705cfSriastradh		return FALSE;
68603b705cfSriastradh
68703b705cfSriastradh	list_add(&info->client_resource, &resource->list);
68803b705cfSriastradh
68903b705cfSriastradh	resource = get_resource(info->drawable_id, frame_event_drawable_type);
69003b705cfSriastradh	if (resource == NULL) {
69103b705cfSriastradh		list_del(&info->client_resource);
69203b705cfSriastradh		return FALSE;
69303b705cfSriastradh	}
69403b705cfSriastradh
69503b705cfSriastradh	list_add(&info->drawable_resource, &resource->list);
69603b705cfSriastradh
69703b705cfSriastradh	return TRUE;
69803b705cfSriastradh}
69903b705cfSriastradh
70003b705cfSriastradhstatic void
70142542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info)
70203b705cfSriastradh{
70303b705cfSriastradh	list_del(&info->client_resource);
70403b705cfSriastradh	list_del(&info->drawable_resource);
70503b705cfSriastradh
70603b705cfSriastradh	if (info->front)
70742542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->front);
70803b705cfSriastradh	if (info->back)
70942542f5fSchristos		I830DRI2DestroyBuffer(NULL, info->back);
71003b705cfSriastradh
711fe8aea9eSmrg	if (info->old_buffer) {
712fe8aea9eSmrg		/* Check that the old buffer still matches the front buffer
713fe8aea9eSmrg		 * in case a mode change occurred before we woke up.
714fe8aea9eSmrg		 */
715fe8aea9eSmrg		if (info->intel->back_buffer == NULL &&
716fe8aea9eSmrg		    info->old_width  == info->intel->scrn->virtualX &&
717fe8aea9eSmrg		    info->old_height == info->intel->scrn->virtualY &&
718fe8aea9eSmrg		    info->old_pitch  == info->intel->front_pitch &&
719fe8aea9eSmrg		    info->old_tiling == info->intel->front_tiling)
720fe8aea9eSmrg			info->intel->back_buffer = info->old_buffer;
721fe8aea9eSmrg		else
722fe8aea9eSmrg			dri_bo_unreference(info->old_buffer);
723fe8aea9eSmrg	}
724fe8aea9eSmrg
72503b705cfSriastradh	free(info);
72603b705cfSriastradh}
72703b705cfSriastradh
72813496ba1Ssnjstatic struct intel_uxa_pixmap *
72903b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back)
73003b705cfSriastradh{
73113496ba1Ssnj	struct intel_uxa_pixmap *new_front = NULL, *new_back;
73203b705cfSriastradh	RegionRec region;
73303b705cfSriastradh
73403b705cfSriastradh	/* Post damage on the front buffer so that listeners, such
73503b705cfSriastradh	 * as DisplayLink know take a copy and shove it over the USB.
73603b705cfSriastradh	 * also for sw cursors.
73703b705cfSriastradh	 */
73803b705cfSriastradh	region.extents.x1 = region.extents.y1 = 0;
73903b705cfSriastradh	region.extents.x2 = front->drawable.width;
74003b705cfSriastradh	region.extents.y2 = front->drawable.height;
74103b705cfSriastradh	region.data = NULL;
74203b705cfSriastradh	DamageRegionAppend(&front->drawable, &region);
74303b705cfSriastradh
74413496ba1Ssnj	new_front = intel_uxa_get_pixmap_private(back);
74513496ba1Ssnj	new_back = intel_uxa_get_pixmap_private(front);
74613496ba1Ssnj	intel_uxa_set_pixmap_private(front, new_front);
74713496ba1Ssnj	intel_uxa_set_pixmap_private(back, new_back);
74803b705cfSriastradh	new_front->busy = 1;
74903b705cfSriastradh	new_back->busy = -1;
75003b705cfSriastradh
75103b705cfSriastradh	DamageRegionProcessPending(&front->drawable);
75203b705cfSriastradh
75303b705cfSriastradh	return new_front;
75403b705cfSriastradh}
75503b705cfSriastradh
75603b705cfSriastradhstatic void
75703b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
75803b705cfSriastradh{
75903b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv, back_priv;
76013496ba1Ssnj	struct intel_uxa_pixmap *new_front;
76103b705cfSriastradh
76203b705cfSriastradh	front_priv = front->driverPrivate;
76303b705cfSriastradh	back_priv = back->driverPrivate;
76403b705cfSriastradh
76503b705cfSriastradh	/* Swap BO names so DRI works */
76603b705cfSriastradh	front->name = back->name;
767fe8aea9eSmrg	back->name = pixmap_flink(front_priv->pixmap);
76803b705cfSriastradh
76903b705cfSriastradh	/* Swap pixmap bos */
77003b705cfSriastradh	new_front = intel_exchange_pixmap_buffers(intel,
77103b705cfSriastradh						  front_priv->pixmap,
77203b705cfSriastradh						  back_priv->pixmap);
77303b705cfSriastradh	dri_bo_unreference (intel->front_buffer);
77403b705cfSriastradh	intel->front_buffer = new_front->bo;
77503b705cfSriastradh	dri_bo_reference (intel->front_buffer);
77603b705cfSriastradh}
77703b705cfSriastradh
77803b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
77903b705cfSriastradh{
78003b705cfSriastradh	drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
78103b705cfSriastradh	assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
78203b705cfSriastradh	return bo;
78303b705cfSriastradh}
78403b705cfSriastradh
78542542f5fSchristosstatic void
78642542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data)
78742542f5fSchristos{
78842542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
78942542f5fSchristos
79042542f5fSchristos        I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000,
79142542f5fSchristos                                 usec % 1000000,
79242542f5fSchristos                                 info);
79342542f5fSchristos}
79442542f5fSchristos
79542542f5fSchristosstatic void
79642542f5fSchristosI830DRI2FlipAbort(void *pageflip_data)
79742542f5fSchristos{
79842542f5fSchristos        DRI2FrameEventPtr info = pageflip_data;
79942542f5fSchristos
80042542f5fSchristos        i830_dri2_del_frame_event(info);
80142542f5fSchristos}
80242542f5fSchristos
80303b705cfSriastradhstatic Bool
804fe8aea9eSmrgallocate_back_buffer(struct intel_screen_private *intel)
80503b705cfSriastradh{
806fe8aea9eSmrg	drm_intel_bo *bo;
807fe8aea9eSmrg	int pitch;
808fe8aea9eSmrg	uint32_t tiling;
80903b705cfSriastradh
810fe8aea9eSmrg	if (intel->back_buffer)
81103b705cfSriastradh		return TRUE;
81203b705cfSriastradh
813fe8aea9eSmrg	bo = intel_allocate_framebuffer(intel->scrn,
814fe8aea9eSmrg					intel->scrn->virtualX,
815fe8aea9eSmrg					intel->scrn->virtualY,
816fe8aea9eSmrg					intel->cpp,
817fe8aea9eSmrg					&pitch, &tiling);
818fe8aea9eSmrg	if (bo == NULL)
819fe8aea9eSmrg		return FALSE;
82003b705cfSriastradh
821fe8aea9eSmrg	if (pitch != intel->front_pitch || tiling != intel->front_tiling) {
822fe8aea9eSmrg		drm_intel_bo_unreference(bo);
82303b705cfSriastradh		return FALSE;
82403b705cfSriastradh	}
82503b705cfSriastradh
826fe8aea9eSmrg	intel->back_buffer = bo;
82703b705cfSriastradh	return TRUE;
82803b705cfSriastradh}
82903b705cfSriastradh
83003b705cfSriastradhstatic Bool
83103b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
83203b705cfSriastradh{
83303b705cfSriastradh	ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen);
83403b705cfSriastradh	struct intel_screen_private *intel = intel_get_screen_private(pScrn);
83503b705cfSriastradh	I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
83603b705cfSriastradh	I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
83703b705cfSriastradh	PixmapPtr front_pixmap = front_priv->pixmap;
83803b705cfSriastradh	PixmapPtr back_pixmap = back_priv->pixmap;
83913496ba1Ssnj	struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap);
84013496ba1Ssnj	struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap);
84103b705cfSriastradh
84203b705cfSriastradh	if (!pScrn->vtSema)
84303b705cfSriastradh		return FALSE;
84403b705cfSriastradh
84542542f5fSchristos	if (I830DRI2DrawableCrtc(drawable) == NULL)
84603b705cfSriastradh		return FALSE;
84703b705cfSriastradh
84803b705cfSriastradh	if (!DRI2CanFlip(drawable))
84903b705cfSriastradh		return FALSE;
85003b705cfSriastradh
85103b705cfSriastradh	if (intel->shadow_present)
85203b705cfSriastradh		return FALSE;
85303b705cfSriastradh
85403b705cfSriastradh	if (!intel->use_pageflipping)
85503b705cfSriastradh		return FALSE;
85603b705cfSriastradh
85703b705cfSriastradh	if (front_pixmap->drawable.width != back_pixmap->drawable.width)
85803b705cfSriastradh		return FALSE;
85903b705cfSriastradh
86003b705cfSriastradh	if (front_pixmap->drawable.height != back_pixmap->drawable.height)
86103b705cfSriastradh		return FALSE;
86203b705cfSriastradh
86303b705cfSriastradh	/* XXX should we be checking depth instead of bpp? */
86403b705cfSriastradh#if 0
86503b705cfSriastradh	if (front_pixmap->drawable.depth != back_pixmap->drawable.depth)
86603b705cfSriastradh		return FALSE;
86703b705cfSriastradh#else
86803b705cfSriastradh	if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
86903b705cfSriastradh		return FALSE;
87003b705cfSriastradh#endif
87103b705cfSriastradh
87203b705cfSriastradh	/* prevent an implicit tiling mode change */
87303b705cfSriastradh	if (front_intel->tiling != back_intel->tiling)
87403b705cfSriastradh		return FALSE;
87503b705cfSriastradh
87642542f5fSchristos	if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2))
87742542f5fSchristos		return FALSE;
87842542f5fSchristos
87903b705cfSriastradh	return TRUE;
88003b705cfSriastradh}
88103b705cfSriastradh
882fe8aea9eSmrgstatic Bool
883fe8aea9eSmrgqueue_flip(struct intel_screen_private *intel,
884fe8aea9eSmrg	   DrawablePtr draw,
885fe8aea9eSmrg	   DRI2FrameEventPtr info)
886fe8aea9eSmrg{
887fe8aea9eSmrg	xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
888fe8aea9eSmrg	I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
889fe8aea9eSmrg	drm_intel_bo *old_back = get_pixmap_bo(priv);
890fe8aea9eSmrg
891fe8aea9eSmrg	if (crtc == NULL)
892fe8aea9eSmrg		return FALSE;
893fe8aea9eSmrg
894fe8aea9eSmrg	if (!can_exchange(draw, info->front, info->back))
895fe8aea9eSmrg		return FALSE;
896fe8aea9eSmrg
897fe8aea9eSmrg	if (!intel_do_pageflip(intel, old_back,
898fe8aea9eSmrg			       intel_crtc_to_pipe(crtc),
899fe8aea9eSmrg			       FALSE, info,
900fe8aea9eSmrg			       I830DRI2FlipComplete, I830DRI2FlipAbort))
901fe8aea9eSmrg		return FALSE;
902fe8aea9eSmrg
903fe8aea9eSmrg#if DRI2INFOREC_VERSION >= 6
904fe8aea9eSmrg	if (intel->use_triple_buffer && allocate_back_buffer(intel)) {
905fe8aea9eSmrg		info->old_width  = intel->scrn->virtualX;
906fe8aea9eSmrg		info->old_height = intel->scrn->virtualY;
907fe8aea9eSmrg		info->old_pitch  = intel->front_pitch;
908fe8aea9eSmrg		info->old_tiling = intel->front_tiling;
909fe8aea9eSmrg		info->old_buffer = intel->front_buffer;
910fe8aea9eSmrg		dri_bo_reference(info->old_buffer);
911fe8aea9eSmrg
912fe8aea9eSmrg		priv = info->front->driverPrivate;
913fe8aea9eSmrg		intel_set_pixmap_bo(priv->pixmap, intel->back_buffer);
914fe8aea9eSmrg
915fe8aea9eSmrg		dri_bo_unreference(intel->back_buffer);
916fe8aea9eSmrg		intel->back_buffer = NULL;
917fe8aea9eSmrg
918fe8aea9eSmrg		DRI2SwapLimit(draw, 2);
919fe8aea9eSmrg	} else
920fe8aea9eSmrg		DRI2SwapLimit(draw, 1);
921fe8aea9eSmrg#endif
922fe8aea9eSmrg
923fe8aea9eSmrg	/* Then flip DRI2 pointers and update the screen pixmap */
924fe8aea9eSmrg	I830DRI2ExchangeBuffers(intel, info->front, info->back);
925fe8aea9eSmrg	return TRUE;
926fe8aea9eSmrg}
927fe8aea9eSmrg
928fe8aea9eSmrgstatic Bool
929fe8aea9eSmrgqueue_swap(struct intel_screen_private *intel,
930fe8aea9eSmrg	   DrawablePtr draw,
931fe8aea9eSmrg	   DRI2FrameEventPtr info)
932fe8aea9eSmrg{
933fe8aea9eSmrg	xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
934fe8aea9eSmrg	drmVBlank vbl;
935fe8aea9eSmrg
936fe8aea9eSmrg	if (crtc == NULL)
937fe8aea9eSmrg		return FALSE;
938fe8aea9eSmrg
939fe8aea9eSmrg	vbl.request.type =
940fe8aea9eSmrg		DRM_VBLANK_RELATIVE |
941fe8aea9eSmrg		DRM_VBLANK_EVENT |
942fe8aea9eSmrg		pipe_select(intel_crtc_to_pipe(crtc));
943fe8aea9eSmrg	vbl.request.sequence = 1;
944fe8aea9eSmrg	vbl.request.signal =
945fe8aea9eSmrg		intel_drm_queue_alloc(intel->scrn, crtc, info,
946fe8aea9eSmrg				      intel_dri2_vblank_handler,
947fe8aea9eSmrg				      intel_dri2_vblank_abort);
948fe8aea9eSmrg	if (vbl.request.signal == 0)
949fe8aea9eSmrg		return FALSE;
950fe8aea9eSmrg
951fe8aea9eSmrg	info->type = DRI2_SWAP;
952fe8aea9eSmrg	if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
953fe8aea9eSmrg		intel_drm_abort_seq(intel->scrn, vbl.request.signal);
954fe8aea9eSmrg		return FALSE;
955fe8aea9eSmrg	}
956fe8aea9eSmrg
957fe8aea9eSmrg	return TRUE;
958fe8aea9eSmrg}
959fe8aea9eSmrg
960fe8aea9eSmrgstatic void I830DRI2FrameEventHandler(unsigned int frame,
961fe8aea9eSmrg				      unsigned int tv_sec,
962fe8aea9eSmrg				      unsigned int tv_usec,
963fe8aea9eSmrg				      DRI2FrameEventPtr swap_info)
96403b705cfSriastradh{
96503b705cfSriastradh	intel_screen_private *intel = swap_info->intel;
96603b705cfSriastradh	DrawablePtr drawable;
96703b705cfSriastradh	int status;
96803b705cfSriastradh
96903b705cfSriastradh	if (!swap_info->drawable_id)
97003b705cfSriastradh		status = BadDrawable;
97103b705cfSriastradh	else
97203b705cfSriastradh		status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
97303b705cfSriastradh					   M_ANY, DixWriteAccess);
97403b705cfSriastradh	if (status != Success) {
97542542f5fSchristos		i830_dri2_del_frame_event(swap_info);
97603b705cfSriastradh		return;
97703b705cfSriastradh	}
97803b705cfSriastradh
97903b705cfSriastradh	switch (swap_info->type) {
98003b705cfSriastradh	case DRI2_FLIP:
98103b705cfSriastradh		/* If we can still flip... */
982fe8aea9eSmrg		if (!queue_flip(intel, drawable, swap_info) &&
983fe8aea9eSmrg		    !queue_swap(intel, drawable, swap_info)) {
984fe8aea9eSmrg		case DRI2_SWAP:
985fe8aea9eSmrg			I830DRI2FallbackBlitSwap(drawable,
986fe8aea9eSmrg						 swap_info->front, swap_info->back);
987fe8aea9eSmrg			DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
988fe8aea9eSmrg					 DRI2_BLIT_COMPLETE,
989fe8aea9eSmrg					 swap_info->client ? swap_info->event_complete : NULL,
990fe8aea9eSmrg					 swap_info->event_data);
991fe8aea9eSmrg			break;
992fe8aea9eSmrg		}
993fe8aea9eSmrg		return;
994fe8aea9eSmrg
99503b705cfSriastradh	case DRI2_WAITMSC:
99603b705cfSriastradh		if (swap_info->client)
99703b705cfSriastradh			DRI2WaitMSCComplete(swap_info->client, drawable,
99803b705cfSriastradh					    frame, tv_sec, tv_usec);
99903b705cfSriastradh		break;
100003b705cfSriastradh	default:
100103b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
100203b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
100303b705cfSriastradh		/* Unknown type */
100403b705cfSriastradh		break;
100503b705cfSriastradh	}
100603b705cfSriastradh
100742542f5fSchristos	i830_dri2_del_frame_event(swap_info);
100803b705cfSriastradh}
100903b705cfSriastradh
1010fe8aea9eSmrgstatic void I830DRI2FlipEventHandler(unsigned int frame,
1011fe8aea9eSmrg				     unsigned int tv_sec,
1012fe8aea9eSmrg				     unsigned int tv_usec,
1013fe8aea9eSmrg				     DRI2FrameEventPtr flip_info)
101403b705cfSriastradh{
101503b705cfSriastradh	struct intel_screen_private *intel = flip_info->intel;
101603b705cfSriastradh	DrawablePtr drawable;
101703b705cfSriastradh
101803b705cfSriastradh	drawable = NULL;
101903b705cfSriastradh	if (flip_info->drawable_id)
102003b705cfSriastradh		dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
102103b705cfSriastradh				  M_ANY, DixWriteAccess);
102203b705cfSriastradh
102303b705cfSriastradh
102403b705cfSriastradh	/* We assume our flips arrive in order, so we don't check the frame */
102503b705cfSriastradh	switch (flip_info->type) {
1026fe8aea9eSmrg	case DRI2_FLIP:
102703b705cfSriastradh	case DRI2_SWAP:
102803b705cfSriastradh		if (!drawable)
102903b705cfSriastradh			break;
103003b705cfSriastradh
103103b705cfSriastradh		/* Check for too small vblank count of pageflip completion, taking wraparound
103203b705cfSriastradh		 * into account. This usually means some defective kms pageflip completion,
103303b705cfSriastradh		 * causing wrong (msc, ust) return values and possible visual corruption.
103403b705cfSriastradh		 */
103503b705cfSriastradh		if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
103603b705cfSriastradh			static int limit = 5;
103703b705cfSriastradh
103803b705cfSriastradh			/* XXX we are currently hitting this path with older
103903b705cfSriastradh			 * kernels, so make it quieter.
104003b705cfSriastradh			 */
104103b705cfSriastradh			if (limit) {
104203b705cfSriastradh				xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
104303b705cfSriastradh					   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
104403b705cfSriastradh					   __func__, frame, flip_info->frame);
104503b705cfSriastradh				limit--;
104603b705cfSriastradh			}
104703b705cfSriastradh
104803b705cfSriastradh			/* All-0 values signal timestamping failure. */
104903b705cfSriastradh			frame = tv_sec = tv_usec = 0;
105003b705cfSriastradh		}
105103b705cfSriastradh
105203b705cfSriastradh		DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
105303b705cfSriastradh				 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
105403b705cfSriastradh				 flip_info->event_data);
105503b705cfSriastradh		break;
105603b705cfSriastradh
105703b705cfSriastradh	default:
105803b705cfSriastradh		xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
105903b705cfSriastradh			   "%s: unknown vblank event received\n", __func__);
106003b705cfSriastradh		/* Unknown type */
106103b705cfSriastradh		break;
106203b705cfSriastradh	}
106303b705cfSriastradh
106442542f5fSchristos	i830_dri2_del_frame_event(flip_info);
106503b705cfSriastradh}
106603b705cfSriastradh
106703b705cfSriastradh/*
106803b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the
106903b705cfSriastradh * appropriate frame.
107003b705cfSriastradh *
107103b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange,
107203b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap
107303b705cfSriastradh * interval for the drawable.
107403b705cfSriastradh *
107503b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap
107603b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame
107703b705cfSriastradh * immediately following the received event.
107803b705cfSriastradh *
107903b705cfSriastradh * The client will be blocked if it tries to perform further GL commands
108003b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the
108103b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if
108203b705cfSriastradh * they access buffers busy with the flip.
108303b705cfSriastradh *
108403b705cfSriastradh * When the swap is complete, the driver should call into the server so it
108503b705cfSriastradh * can send any swap complete events that have been requested.
108603b705cfSriastradh */
108703b705cfSriastradhstatic int
108803b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
108903b705cfSriastradh		     DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
109003b705cfSriastradh		     CARD64 remainder, DRI2SwapEventPtr func, void *data)
109103b705cfSriastradh{
109203b705cfSriastradh	ScreenPtr screen = draw->pScreen;
109303b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
109403b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
109503b705cfSriastradh	drmVBlank vbl;
109642542f5fSchristos	int ret;
109742542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
109842542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
109942542f5fSchristos        int flip = 0;
110003b705cfSriastradh	DRI2FrameEventPtr swap_info = NULL;
110142542f5fSchristos	uint64_t current_msc, current_ust;
110242542f5fSchristos        uint64_t request_msc;
110342542f5fSchristos        uint32_t seq;
110403b705cfSriastradh
110503b705cfSriastradh	/* Drawable not displayed... just complete the swap */
110603b705cfSriastradh	if (pipe == -1)
110703b705cfSriastradh	    goto blit_fallback;
110803b705cfSriastradh
110903b705cfSriastradh	swap_info = calloc(1, sizeof(DRI2FrameEventRec));
111003b705cfSriastradh	if (!swap_info)
111103b705cfSriastradh	    goto blit_fallback;
111203b705cfSriastradh
111303b705cfSriastradh	swap_info->intel = intel;
111403b705cfSriastradh	swap_info->drawable_id = draw->id;
111503b705cfSriastradh	swap_info->client = client;
111603b705cfSriastradh	swap_info->event_complete = func;
111703b705cfSriastradh	swap_info->event_data = data;
111803b705cfSriastradh	swap_info->front = front;
111903b705cfSriastradh	swap_info->back = back;
1120fe8aea9eSmrg	swap_info->type = DRI2_SWAP;
112103b705cfSriastradh
112203b705cfSriastradh	if (!i830_dri2_add_frame_event(swap_info)) {
112303b705cfSriastradh	    free(swap_info);
112403b705cfSriastradh	    swap_info = NULL;
112503b705cfSriastradh	    goto blit_fallback;
112603b705cfSriastradh	}
112703b705cfSriastradh
112803b705cfSriastradh	I830DRI2ReferenceBuffer(front);
112903b705cfSriastradh	I830DRI2ReferenceBuffer(back);
113003b705cfSriastradh
113142542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
113242542f5fSchristos	if (ret)
113342542f5fSchristos	    goto blit_fallback;
113403b705cfSriastradh
1135fe8aea9eSmrg	/*
1136fe8aea9eSmrg	 * If we can, schedule the flip directly from here rather
1137fe8aea9eSmrg	 * than waiting for an event from the kernel for the current
1138fe8aea9eSmrg	 * (or a past) MSC.
1139fe8aea9eSmrg	 */
1140fe8aea9eSmrg	if (divisor == 0 &&
1141fe8aea9eSmrg	    current_msc >= *target_msc &&
1142fe8aea9eSmrg	    queue_flip(intel, draw, swap_info))
1143fe8aea9eSmrg		return TRUE;
1144fe8aea9eSmrg
114503b705cfSriastradh	if (can_exchange(draw, front, back)) {
1146fe8aea9eSmrg		swap_info->type = DRI2_FLIP;
1147fe8aea9eSmrg		/* Flips need to be submitted one frame before */
1148fe8aea9eSmrg		if (*target_msc > 0)
1149fe8aea9eSmrg			--*target_msc;
1150fe8aea9eSmrg		flip = 1;
115103b705cfSriastradh	}
115203b705cfSriastradh
1153fe8aea9eSmrg#if DRI2INFOREC_VERSION >= 6
1154fe8aea9eSmrg	DRI2SwapLimit(draw, 1);
1155fe8aea9eSmrg#endif
115603b705cfSriastradh
115703b705cfSriastradh	/*
115803b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc
115903b705cfSriastradh	 * we just need to make sure target_msc passes before initiating
116003b705cfSriastradh	 * the swap.
116103b705cfSriastradh	 */
116203b705cfSriastradh	if (divisor == 0 || current_msc < *target_msc) {
116303b705cfSriastradh		vbl.request.type =
116403b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
116503b705cfSriastradh
116603b705cfSriastradh		/* If non-pageflipping, but blitting/exchanging, we need to use
116703b705cfSriastradh		 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
116803b705cfSriastradh		 * on.
116903b705cfSriastradh		 */
117003b705cfSriastradh		if (flip == 0)
117103b705cfSriastradh			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
117203b705cfSriastradh
117303b705cfSriastradh		/* If target_msc already reached or passed, set it to
117403b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
117503b705cfSriastradh		 * to the caller. This makes swap_interval logic more robust.
117603b705cfSriastradh		 */
1177fe8aea9eSmrg		if (current_msc > *target_msc)
117803b705cfSriastradh			*target_msc = current_msc;
117903b705cfSriastradh
118042542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
118142542f5fSchristos                if (!seq)
118242542f5fSchristos                        goto blit_fallback;
118342542f5fSchristos
118442542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc);
118542542f5fSchristos		vbl.request.signal = seq;
118642542f5fSchristos
118703b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
118803b705cfSriastradh		if (ret) {
118903b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
119003b705cfSriastradh				   "divisor 0 get vblank counter failed: %s\n",
119103b705cfSriastradh				   strerror(errno));
1192fe8aea9eSmrg			intel_drm_abort_seq(intel->scrn, seq);
1193fe8aea9eSmrg			swap_info = NULL;
119403b705cfSriastradh			goto blit_fallback;
119503b705cfSriastradh		}
119603b705cfSriastradh
119742542f5fSchristos                *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
119803b705cfSriastradh		swap_info->frame = *target_msc;
119903b705cfSriastradh
120003b705cfSriastradh		return TRUE;
120103b705cfSriastradh	}
120203b705cfSriastradh
120303b705cfSriastradh	/*
120403b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
120503b705cfSriastradh	 * and we need to queue an event that will satisfy the divisor/remainder
120603b705cfSriastradh	 * equation.
120703b705cfSriastradh	 */
120803b705cfSriastradh	vbl.request.type =
120903b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
121003b705cfSriastradh	if (flip == 0)
121103b705cfSriastradh		vbl.request.type |= DRM_VBLANK_NEXTONMISS;
121203b705cfSriastradh
121342542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
121442542f5fSchristos                remainder;
121503b705cfSriastradh
121603b705cfSriastradh	/*
121703b705cfSriastradh	 * If the calculated deadline vbl.request.sequence is smaller than
121803b705cfSriastradh	 * or equal to current_msc, it means we've passed the last point
121903b705cfSriastradh	 * when effective onset frame seq could satisfy
122003b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
122103b705cfSriastradh	 * this will happen.
122203b705cfSriastradh
122303b705cfSriastradh	 * This comparison takes the 1 frame swap delay in pageflipping mode
122403b705cfSriastradh	 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay
122503b705cfSriastradh	 * if we are blitting/exchanging instead of flipping.
122603b705cfSriastradh	 */
122742542f5fSchristos	if (request_msc <= current_msc)
122842542f5fSchristos		request_msc += divisor;
122942542f5fSchristos
123042542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
123142542f5fSchristos        if (!seq)
123242542f5fSchristos                goto blit_fallback;
123303b705cfSriastradh
123403b705cfSriastradh	/* Account for 1 frame extra pageflip delay if flip > 0 */
123542542f5fSchristos        vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip;
123642542f5fSchristos	vbl.request.signal = seq;
123703b705cfSriastradh
123803b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
123903b705cfSriastradh	if (ret) {
124003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
124103b705cfSriastradh			   "final get vblank counter failed: %s\n",
124203b705cfSriastradh			   strerror(errno));
124303b705cfSriastradh		goto blit_fallback;
124403b705cfSriastradh	}
124503b705cfSriastradh
124603b705cfSriastradh	/* Adjust returned value for 1 fame pageflip offset of flip > 0 */
124742542f5fSchristos	*target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip);
124803b705cfSriastradh	swap_info->frame = *target_msc;
124903b705cfSriastradh
125003b705cfSriastradh	return TRUE;
125103b705cfSriastradh
125203b705cfSriastradhblit_fallback:
125303b705cfSriastradh	I830DRI2FallbackBlitSwap(draw, front, back);
125403b705cfSriastradh	DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
125503b705cfSriastradh	if (swap_info)
125642542f5fSchristos	    i830_dri2_del_frame_event(swap_info);
125703b705cfSriastradh	*target_msc = 0; /* offscreen, so zero out target vblank count */
125803b705cfSriastradh	return TRUE;
125903b705cfSriastradh}
126003b705cfSriastradh
126103b705cfSriastradhstatic uint64_t gettime_us(void)
126203b705cfSriastradh{
126303b705cfSriastradh	struct timespec tv;
126403b705cfSriastradh
126503b705cfSriastradh	if (clock_gettime(CLOCK_MONOTONIC, &tv))
126603b705cfSriastradh		return 0;
126703b705cfSriastradh
126803b705cfSriastradh	return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
126903b705cfSriastradh}
127003b705cfSriastradh
127103b705cfSriastradh/*
127203b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's
127303b705cfSriastradh * crtc.
127403b705cfSriastradh */
127503b705cfSriastradhstatic int
127603b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
127703b705cfSriastradh{
127803b705cfSriastradh	ScreenPtr screen = draw->pScreen;
127903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
128042542f5fSchristos	int ret;
128142542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
128203b705cfSriastradh
128303b705cfSriastradh	/* Drawable not displayed, make up a *monotonic* value */
128442542f5fSchristos	if (crtc == NULL) {
128542542f5fSchristosfail:
128603b705cfSriastradh		*ust = gettime_us();
128703b705cfSriastradh		*msc = 0;
128803b705cfSriastradh		return TRUE;
128903b705cfSriastradh	}
129003b705cfSriastradh
129142542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust);
129203b705cfSriastradh	if (ret) {
129303b705cfSriastradh		static int limit = 5;
129403b705cfSriastradh		if (limit) {
129503b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
129603b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
129703b705cfSriastradh				   __FUNCTION__, __LINE__,
129803b705cfSriastradh				   strerror(errno));
129903b705cfSriastradh			limit--;
130003b705cfSriastradh		}
130142542f5fSchristos		goto fail;
130203b705cfSriastradh	}
130303b705cfSriastradh
130403b705cfSriastradh	return TRUE;
130503b705cfSriastradh}
130603b705cfSriastradh
130703b705cfSriastradh/*
130803b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied.
130903b705cfSriastradh *
131003b705cfSriastradh * We need to handle the event and ask the server to wake up the client when
131103b705cfSriastradh * we receive it.
131203b705cfSriastradh */
131303b705cfSriastradhstatic int
131403b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
131503b705cfSriastradh			CARD64 divisor, CARD64 remainder)
131603b705cfSriastradh{
131703b705cfSriastradh	ScreenPtr screen = draw->pScreen;
131803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
131903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
132003b705cfSriastradh	DRI2FrameEventPtr wait_info;
132103b705cfSriastradh	drmVBlank vbl;
132242542f5fSchristos	int ret;
132342542f5fSchristos        xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
132442542f5fSchristos        int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
132542542f5fSchristos	CARD64 current_msc, current_ust, request_msc;
132642542f5fSchristos        uint32_t seq;
132703b705cfSriastradh
132803b705cfSriastradh	/* Drawable not visible, return immediately */
132903b705cfSriastradh	if (pipe == -1)
133003b705cfSriastradh		goto out_complete;
133103b705cfSriastradh
133203b705cfSriastradh	wait_info = calloc(1, sizeof(DRI2FrameEventRec));
133303b705cfSriastradh	if (!wait_info)
133403b705cfSriastradh		goto out_complete;
133503b705cfSriastradh
133603b705cfSriastradh	wait_info->intel = intel;
133703b705cfSriastradh	wait_info->drawable_id = draw->id;
133803b705cfSriastradh	wait_info->client = client;
133903b705cfSriastradh	wait_info->type = DRI2_WAITMSC;
134003b705cfSriastradh
134103b705cfSriastradh	if (!i830_dri2_add_frame_event(wait_info)) {
134203b705cfSriastradh	    free(wait_info);
134303b705cfSriastradh	    goto out_complete;
134403b705cfSriastradh	}
134503b705cfSriastradh
134603b705cfSriastradh	/* Get current count */
134742542f5fSchristos        ret = intel_get_crtc_msc_ust(scrn, crtc, &current_msc, &current_ust);
134842542f5fSchristos	if (ret)
134942542f5fSchristos	    goto out_free;
135003b705cfSriastradh
135103b705cfSriastradh	/*
135203b705cfSriastradh	 * If divisor is zero, or current_msc is smaller than target_msc,
135303b705cfSriastradh	 * we just need to make sure target_msc passes  before waking up the
135403b705cfSriastradh	 * client.
135503b705cfSriastradh	 */
135603b705cfSriastradh	if (divisor == 0 || current_msc < target_msc) {
135703b705cfSriastradh		/* If target_msc already reached or passed, set it to
135803b705cfSriastradh		 * current_msc to ensure we return a reasonable value back
135903b705cfSriastradh		 * to the caller. This keeps the client from continually
136003b705cfSriastradh		 * sending us MSC targets from the past by forcibly updating
136103b705cfSriastradh		 * their count on this call.
136203b705cfSriastradh		 */
136342542f5fSchristos                seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
136442542f5fSchristos                if (!seq)
136542542f5fSchristos                        goto out_free;
136642542f5fSchristos
136703b705cfSriastradh		if (current_msc >= target_msc)
136803b705cfSriastradh			target_msc = current_msc;
136903b705cfSriastradh		vbl.request.type =
137003b705cfSriastradh			DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
137142542f5fSchristos		vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc);
137242542f5fSchristos		vbl.request.signal = seq;
137342542f5fSchristos
137403b705cfSriastradh		ret = drmWaitVBlank(intel->drmSubFD, &vbl);
137503b705cfSriastradh		if (ret) {
137603b705cfSriastradh			static int limit = 5;
137703b705cfSriastradh			if (limit) {
137803b705cfSriastradh				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
137903b705cfSriastradh					   "%s:%d get vblank counter failed: %s\n",
138003b705cfSriastradh					   __FUNCTION__, __LINE__,
138103b705cfSriastradh					   strerror(errno));
138203b705cfSriastradh				limit--;
138303b705cfSriastradh			}
1384fe8aea9eSmrg			intel_drm_abort_seq(intel->scrn, seq);
1385fe8aea9eSmrg			goto out_complete;
138603b705cfSriastradh		}
138703b705cfSriastradh
138842542f5fSchristos		wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
138903b705cfSriastradh		DRI2BlockClient(client, draw);
139003b705cfSriastradh		return TRUE;
139103b705cfSriastradh	}
139203b705cfSriastradh
139303b705cfSriastradh	/*
139403b705cfSriastradh	 * If we get here, target_msc has already passed or we don't have one,
139503b705cfSriastradh	 * so we queue an event that will satisfy the divisor/remainder equation.
139603b705cfSriastradh	 */
139703b705cfSriastradh	vbl.request.type =
139803b705cfSriastradh		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
139903b705cfSriastradh
140042542f5fSchristos        request_msc = current_msc - (current_msc % divisor) +
140142542f5fSchristos                remainder;
140203b705cfSriastradh	/*
140303b705cfSriastradh	 * If calculated remainder is larger than requested remainder,
140403b705cfSriastradh	 * it means we've passed the last point where
140503b705cfSriastradh	 * seq % divisor == remainder, so we need to wait for the next time
140603b705cfSriastradh	 * that will happen.
140703b705cfSriastradh	 */
140803b705cfSriastradh	if ((current_msc % divisor) >= remainder)
140942542f5fSchristos                request_msc += divisor;
141042542f5fSchristos
141142542f5fSchristos        seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
141242542f5fSchristos        if (!seq)
141342542f5fSchristos                goto out_free;
141442542f5fSchristos
141542542f5fSchristos	vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc);
141642542f5fSchristos	vbl.request.signal = seq;
141703b705cfSriastradh
141803b705cfSriastradh	ret = drmWaitVBlank(intel->drmSubFD, &vbl);
141903b705cfSriastradh	if (ret) {
142003b705cfSriastradh		static int limit = 5;
142103b705cfSriastradh		if (limit) {
142203b705cfSriastradh			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
142303b705cfSriastradh				   "%s:%d get vblank counter failed: %s\n",
142403b705cfSriastradh				   __FUNCTION__, __LINE__,
142503b705cfSriastradh				   strerror(errno));
142603b705cfSriastradh			limit--;
142703b705cfSriastradh		}
1428fe8aea9eSmrg		intel_drm_abort_seq(intel->scrn, seq);
1429fe8aea9eSmrg		goto out_complete;
143003b705cfSriastradh	}
143103b705cfSriastradh
143242542f5fSchristos	wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
143303b705cfSriastradh	DRI2BlockClient(client, draw);
143403b705cfSriastradh
143503b705cfSriastradh	return TRUE;
143603b705cfSriastradh
143703b705cfSriastradhout_free:
143842542f5fSchristos	i830_dri2_del_frame_event(wait_info);
143903b705cfSriastradhout_complete:
144003b705cfSriastradh	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
144103b705cfSriastradh	return TRUE;
144203b705cfSriastradh}
144303b705cfSriastradh
144403b705cfSriastradhstatic int dri2_server_generation;
144503b705cfSriastradh#endif
144603b705cfSriastradh
144703b705cfSriastradhstatic int has_i830_dri(void)
144803b705cfSriastradh{
144903b705cfSriastradh	return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
145003b705cfSriastradh}
145103b705cfSriastradh
1452fe8aea9eSmrgstatic int
1453fe8aea9eSmrgnamecmp(const char *s1, const char *s2)
1454fe8aea9eSmrg{
1455fe8aea9eSmrg	char c1, c2;
1456fe8aea9eSmrg
1457fe8aea9eSmrg	if (!s1 || *s1 == 0) {
1458fe8aea9eSmrg		if (!s2 || *s2 == 0)
1459fe8aea9eSmrg			return 0;
1460fe8aea9eSmrg		else
1461fe8aea9eSmrg			return 1;
1462fe8aea9eSmrg	}
1463fe8aea9eSmrg
1464fe8aea9eSmrg	while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1465fe8aea9eSmrg		s1++;
1466fe8aea9eSmrg
1467fe8aea9eSmrg	while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1468fe8aea9eSmrg		s2++;
1469fe8aea9eSmrg
1470fe8aea9eSmrg	c1 = isupper(*s1) ? tolower(*s1) : *s1;
1471fe8aea9eSmrg	c2 = isupper(*s2) ? tolower(*s2) : *s2;
1472fe8aea9eSmrg	while (c1 == c2) {
1473fe8aea9eSmrg		if (c1 == '\0')
1474fe8aea9eSmrg			return 0;
1475fe8aea9eSmrg
1476fe8aea9eSmrg		s1++;
1477fe8aea9eSmrg		while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
1478fe8aea9eSmrg			s1++;
1479fe8aea9eSmrg
1480fe8aea9eSmrg		s2++;
1481fe8aea9eSmrg		while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
1482fe8aea9eSmrg			s2++;
1483fe8aea9eSmrg
1484fe8aea9eSmrg		c1 = isupper(*s1) ? tolower(*s1) : *s1;
1485fe8aea9eSmrg		c2 = isupper(*s2) ? tolower(*s2) : *s2;
1486fe8aea9eSmrg	}
1487fe8aea9eSmrg
1488fe8aea9eSmrg	return c1 - c2;
1489fe8aea9eSmrg}
1490fe8aea9eSmrg
1491fe8aea9eSmrgstatic Bool is_level(const char **str)
1492fe8aea9eSmrg{
1493fe8aea9eSmrg	const char *s = *str;
1494fe8aea9eSmrg	char *end;
1495fe8aea9eSmrg	unsigned val;
1496fe8aea9eSmrg
1497fe8aea9eSmrg	if (s == NULL || *s == '\0')
1498fe8aea9eSmrg		return TRUE;
1499fe8aea9eSmrg
1500fe8aea9eSmrg	if (namecmp(s, "on") == 0)
1501fe8aea9eSmrg		return TRUE;
1502fe8aea9eSmrg	if (namecmp(s, "true") == 0)
1503fe8aea9eSmrg		return TRUE;
1504fe8aea9eSmrg	if (namecmp(s, "yes") == 0)
1505fe8aea9eSmrg		return TRUE;
1506fe8aea9eSmrg
1507fe8aea9eSmrg	if (namecmp(s, "0") == 0)
1508fe8aea9eSmrg		return TRUE;
1509fe8aea9eSmrg	if (namecmp(s, "off") == 0)
1510fe8aea9eSmrg		return TRUE;
1511fe8aea9eSmrg	if (namecmp(s, "false") == 0)
1512fe8aea9eSmrg		return TRUE;
1513fe8aea9eSmrg	if (namecmp(s, "no") == 0)
1514fe8aea9eSmrg		return TRUE;
1515fe8aea9eSmrg
1516fe8aea9eSmrg	val = strtoul(s, &end, 0);
1517fe8aea9eSmrg	if (val && *end == '\0')
1518fe8aea9eSmrg		return TRUE;
1519fe8aea9eSmrg	if (val && *end == ':')
1520fe8aea9eSmrg		*str = end + 1;
1521fe8aea9eSmrg	return FALSE;
1522fe8aea9eSmrg}
1523fe8aea9eSmrg
1524fe8aea9eSmrgstatic const char *options_get_dri(intel_screen_private *intel)
152503b705cfSriastradh{
152642542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
1527fe8aea9eSmrg	return xf86GetOptValString(intel->Options, OPTION_DRI);
1528fe8aea9eSmrg#else
1529fe8aea9eSmrg	return NULL;
1530fe8aea9eSmrg#endif
1531fe8aea9eSmrg}
153203b705cfSriastradh
1533fe8aea9eSmrgstatic const char *dri_driver_name(intel_screen_private *intel)
1534fe8aea9eSmrg{
1535fe8aea9eSmrg	const char *s = options_get_dri(intel);
1536fe8aea9eSmrg
1537fe8aea9eSmrg	if (is_level(&s)) {
153803b705cfSriastradh		if (INTEL_INFO(intel)->gen < 030)
153903b705cfSriastradh			return has_i830_dri() ? "i830" : "i915";
154003b705cfSriastradh		else if (INTEL_INFO(intel)->gen < 040)
154103b705cfSriastradh			return "i915";
154203b705cfSriastradh		else
154303b705cfSriastradh			return "i965";
154403b705cfSriastradh	}
154503b705cfSriastradh
154603b705cfSriastradh	return s;
154703b705cfSriastradh}
154803b705cfSriastradh
154903b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen)
155003b705cfSriastradh{
155103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
155203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
155303b705cfSriastradh	DRI2InfoRec info;
155442542f5fSchristos	int dri2scr_major = 1;
155542542f5fSchristos	int dri2scr_minor = 0;
155603b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
155742542f5fSchristos	const char *driverNames[2];
155803b705cfSriastradh#endif
155903b705cfSriastradh
156003b705cfSriastradh	if (intel->force_fallback) {
156103b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
156203b705cfSriastradh			   "cannot enable DRI2 whilst forcing software fallbacks\n");
156303b705cfSriastradh		return FALSE;
156403b705cfSriastradh	}
156503b705cfSriastradh
156603b705cfSriastradh	if (xf86LoaderCheckSymbol("DRI2Version"))
156742542f5fSchristos		DRI2Version(&dri2scr_major, &dri2scr_minor);
156803b705cfSriastradh
156942542f5fSchristos	if (dri2scr_minor < 1) {
157003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
157103b705cfSriastradh			   "DRI2 requires DRI2 module version 1.1.0 or later\n");
157203b705cfSriastradh		return FALSE;
157303b705cfSriastradh	}
157403b705cfSriastradh
157503b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
157603b705cfSriastradh	if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID)))
157703b705cfSriastradh		return FALSE;
157803b705cfSriastradh#else
157903b705cfSriastradh	if (!dixRequestPrivate(&i830_client_key, sizeof(XID)))
158003b705cfSriastradh		return FALSE;
158103b705cfSriastradh#endif
158203b705cfSriastradh
158303b705cfSriastradh
158403b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
158503b705cfSriastradh	if (serverGeneration != dri2_server_generation) {
158603b705cfSriastradh	    dri2_server_generation = serverGeneration;
158703b705cfSriastradh	    if (!i830_dri2_register_frame_event_resource_types()) {
158803b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
158903b705cfSriastradh			   "Cannot register DRI2 frame event resources\n");
159003b705cfSriastradh		return FALSE;
159103b705cfSriastradh	    }
159203b705cfSriastradh	}
159303b705cfSriastradh#endif
159403b705cfSriastradh
159503b705cfSriastradh	intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD);
159603b705cfSriastradh	memset(&info, '\0', sizeof(info));
159703b705cfSriastradh	info.fd = intel->drmSubFD;
159803b705cfSriastradh	info.driverName = dri_driver_name(intel);
159903b705cfSriastradh	info.deviceName = intel->deviceName;
160003b705cfSriastradh
160103b705cfSriastradh#if DRI2INFOREC_VERSION == 1
160203b705cfSriastradh	info.version = 1;
160303b705cfSriastradh	info.CreateBuffers = I830DRI2CreateBuffers;
160403b705cfSriastradh	info.DestroyBuffers = I830DRI2DestroyBuffers;
160503b705cfSriastradh#elif DRI2INFOREC_VERSION == 2
160603b705cfSriastradh	/* The ABI between 2 and 3 was broken so we could get rid of
160703b705cfSriastradh	 * the multi-buffer alloc functions.  Make sure we indicate the
160803b705cfSriastradh	 * right version so DRI2 can reject us if it's version 3 or above. */
160903b705cfSriastradh	info.version = 2;
161003b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
161103b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
161203b705cfSriastradh#else
161303b705cfSriastradh	info.version = 3;
161403b705cfSriastradh	info.CreateBuffer = I830DRI2CreateBuffer;
161503b705cfSriastradh	info.DestroyBuffer = I830DRI2DestroyBuffer;
161603b705cfSriastradh#endif
161703b705cfSriastradh
161803b705cfSriastradh	info.CopyRegion = I830DRI2CopyRegion;
161903b705cfSriastradh#if DRI2INFOREC_VERSION >= 4
162003b705cfSriastradh	info.version = 4;
162103b705cfSriastradh	info.ScheduleSwap = I830DRI2ScheduleSwap;
162203b705cfSriastradh	info.GetMSC = I830DRI2GetMSC;
162303b705cfSriastradh	info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
162442542f5fSchristos	info.numDrivers = 2;
162503b705cfSriastradh	info.driverNames = driverNames;
162603b705cfSriastradh	driverNames[0] = info.driverName;
1627fe8aea9eSmrg	driverNames[1] = "va_gl";
162803b705cfSriastradh#endif
162903b705cfSriastradh
163003b705cfSriastradh	return DRI2ScreenInit(screen, &info);
163103b705cfSriastradh}
163203b705cfSriastradh
163303b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen)
163403b705cfSriastradh{
163503b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
163603b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
163703b705cfSriastradh
163803b705cfSriastradh	DRI2CloseScreen(screen);
163903b705cfSriastradh	drmFree(intel->deviceName);
164003b705cfSriastradh}
1641