1/**************************************************************************
2
3Copyright 2001 VA Linux Systems Inc., Fremont, California.
4Copyright © 2002 by David Dawes
5
6All Rights Reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the "Software"),
10to deal in the Software without restriction, including without limitation
11on the rights to use, copy, modify, merge, publish, distribute, sub
12license, and/or sell copies of the Software, and to permit persons to whom
13the Software is furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice (including the next
16paragraph) shall be included in all copies or substantial portions of the
17Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27**************************************************************************/
28
29/*
30 * Authors: Jeff Hartmann <jhartmann@valinux.com>
31 *          David Dawes <dawes@xfree86.org>
32 *          Keith Whitwell <keith@tungstengraphics.com>
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include <stdio.h>
40#include <string.h>
41#include <assert.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <sys/ioctl.h>
45#include <errno.h>
46#include <unistd.h>
47#include <fcntl.h>
48
49#include "xf86.h"
50#include "xf86_OSproc.h"
51#include "xf86Priv.h"
52
53#include "xf86PciInfo.h"
54#include "xf86Pci.h"
55
56#include "windowstr.h"
57#include "shadow.h"
58
59#include "GL/glxtokens.h"
60
61#include "i830.h"
62#include "i830_dri.h"
63
64#include "i915_drm.h"
65
66#include "dri2.h"
67
68#ifdef DRI2
69#if DRI2INFOREC_VERSION >= 1
70#define USE_DRI2_1_1_0
71#endif
72
73extern XF86ModuleData dri2ModuleData;
74#endif
75
76typedef struct {
77    PixmapPtr pPixmap;
78    unsigned int attachment;
79} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
80
81#ifndef USE_DRI2_1_1_0
82static DRI2BufferPtr
83I830DRI2CreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count)
84{
85    ScreenPtr pScreen = pDraw->pScreen;
86    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
87    I830Ptr pI830 = I830PTR(pScrn);
88    DRI2BufferPtr buffers;
89    dri_bo *bo;
90    int i;
91    I830DRI2BufferPrivatePtr privates;
92    PixmapPtr pPixmap, pDepthPixmap;
93
94    buffers = xcalloc(count, sizeof *buffers);
95    if (buffers == NULL)
96	return NULL;
97    privates = xcalloc(count, sizeof *privates);
98    if (privates == NULL) {
99	xfree(buffers);
100	return NULL;
101    }
102
103    pDepthPixmap = NULL;
104    for (i = 0; i < count; i++) {
105	if (attachments[i] == DRI2BufferFrontLeft) {
106	    pPixmap = get_drawable_pixmap(pDraw);
107	    pPixmap->refcnt++;
108	} else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
109	    pPixmap = pDepthPixmap;
110	    pPixmap->refcnt++;
111	} else {
112	    unsigned int hint = 0;
113
114	    switch (attachments[i]) {
115	    case DRI2BufferDepth:
116		if (SUPPORTS_YTILING(pI830))
117		    hint = INTEL_CREATE_PIXMAP_TILING_Y;
118		else
119		    hint = INTEL_CREATE_PIXMAP_TILING_X;
120		break;
121	    case DRI2BufferFakeFrontLeft:
122	    case DRI2BufferFakeFrontRight:
123	    case DRI2BufferBackLeft:
124	    case DRI2BufferBackRight:
125		    hint = INTEL_CREATE_PIXMAP_TILING_X;
126		break;
127	    }
128
129	    if (!pI830->tiling ||
130		(!IS_I965G(pI830) && !pI830->kernel_exec_fencing))
131		hint = 0;
132
133	    pPixmap = (*pScreen->CreatePixmap)(pScreen,
134					       pDraw->width,
135					       pDraw->height,
136					       pDraw->depth,
137					       hint);
138
139	}
140
141	if (attachments[i] == DRI2BufferDepth)
142	    pDepthPixmap = pPixmap;
143
144	buffers[i].attachment = attachments[i];
145	buffers[i].pitch = pPixmap->devKind;
146	buffers[i].cpp = pPixmap->drawable.bitsPerPixel / 8;
147	buffers[i].driverPrivate = &privates[i];
148	buffers[i].flags = 0; /* not tiled */
149	privates[i].pPixmap = pPixmap;
150	privates[i].attachment = attachments[i];
151
152	bo = i830_get_pixmap_bo (pPixmap);
153	if (dri_bo_flink(bo, &buffers[i].name) != 0) {
154	    /* failed to name buffer */
155	}
156
157    }
158
159    return buffers;
160}
161
162#else
163
164static DRI2Buffer2Ptr
165I830DRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
166		     unsigned int format)
167{
168    ScreenPtr pScreen = pDraw->pScreen;
169    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
170    I830Ptr pI830 = I830PTR(pScrn);
171    DRI2Buffer2Ptr buffer;
172    dri_bo *bo;
173    I830DRI2BufferPrivatePtr privates;
174    PixmapPtr pPixmap;
175
176    buffer = xcalloc(1, sizeof *buffer);
177    if (buffer == NULL)
178	return NULL;
179    privates = xcalloc(1, sizeof *privates);
180    if (privates == NULL) {
181	xfree(buffer);
182	return NULL;
183    }
184
185    if (attachment == DRI2BufferFrontLeft) {
186	pPixmap = get_drawable_pixmap(pDraw);
187	pPixmap->refcnt++;
188    } else {
189	unsigned int hint = 0;
190
191	switch (attachment) {
192	case DRI2BufferDepth:
193	case DRI2BufferDepthStencil:
194	    if (SUPPORTS_YTILING(pI830))
195		hint = INTEL_CREATE_PIXMAP_TILING_Y;
196	    else
197		hint = INTEL_CREATE_PIXMAP_TILING_X;
198	    break;
199	case DRI2BufferFakeFrontLeft:
200	case DRI2BufferFakeFrontRight:
201	case DRI2BufferBackLeft:
202	case DRI2BufferBackRight:
203	    hint = INTEL_CREATE_PIXMAP_TILING_X;
204	    break;
205	}
206
207	if (!pI830->tiling ||
208	    (!IS_I965G(pI830) && !pI830->kernel_exec_fencing))
209	    hint = 0;
210
211	pPixmap = (*pScreen->CreatePixmap)(pScreen,
212					   pDraw->width,
213					   pDraw->height,
214					   (format != 0)?format:pDraw->depth,
215					   hint);
216
217    }
218
219
220    buffer->attachment = attachment;
221    buffer->pitch = pPixmap->devKind;
222    buffer->cpp = pPixmap->drawable.bitsPerPixel / 8;
223    buffer->driverPrivate = privates;
224    buffer->format = format;
225    buffer->flags = 0; /* not tiled */
226    privates->pPixmap = pPixmap;
227    privates->attachment = attachment;
228
229    bo = i830_get_pixmap_bo (pPixmap);
230    if (dri_bo_flink(bo, &buffer->name) != 0) {
231	/* failed to name buffer */
232    }
233
234    return buffer;
235}
236
237#endif
238
239#ifndef USE_DRI2_1_1_0
240
241static void
242I830DRI2DestroyBuffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count)
243{
244    ScreenPtr pScreen = pDraw->pScreen;
245    I830DRI2BufferPrivatePtr private;
246    int i;
247
248    for (i = 0; i < count; i++)
249    {
250	private = buffers[i].driverPrivate;
251	(*pScreen->DestroyPixmap)(private->pPixmap);
252    }
253
254    if (buffers)
255    {
256	xfree(buffers[0].driverPrivate);
257	xfree(buffers);
258    }
259}
260
261#else
262
263static void
264I830DRI2DestroyBuffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
265{
266    if (buffer) {
267	I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
268	ScreenPtr pScreen = pDraw->pScreen;
269
270	(*pScreen->DestroyPixmap)(private->pPixmap);
271
272	xfree(private);
273	xfree(buffer);
274    }
275}
276
277#endif
278
279static void
280I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
281		   DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
282{
283    I830DRI2BufferPrivatePtr srcPrivate = pSrcBuffer->driverPrivate;
284    I830DRI2BufferPrivatePtr dstPrivate = pDstBuffer->driverPrivate;
285    ScreenPtr pScreen = pDraw->pScreen;
286    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
287    I830Ptr pI830 = I830PTR(pScrn);
288    DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft)
289	? pDraw : &srcPrivate->pPixmap->drawable;
290    DrawablePtr dst = (dstPrivate->attachment == DRI2BufferFrontLeft)
291	? pDraw : &dstPrivate->pPixmap->drawable;
292    RegionPtr pCopyClip;
293    GCPtr pGC;
294
295    pGC = GetScratchGC(pDraw->depth, pScreen);
296    pCopyClip = REGION_CREATE(pScreen, NULL, 0);
297    REGION_COPY(pScreen, pCopyClip, pRegion);
298    (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0);
299    ValidateGC(dst, pGC);
300
301    /* Wait for the scanline to be outside the region to be copied */
302    if (pixmap_is_scanout(get_drawable_pixmap(dst)) && pI830->swapbuffers_wait) {
303	BoxPtr box;
304	BoxRec crtcbox;
305	int y1, y2;
306	int pipe = -1, event, load_scan_lines_pipe;
307	xf86CrtcPtr crtc;
308
309	box = REGION_EXTENTS(unused, pGC->pCompositeClip);
310	crtc = i830_covering_crtc(pScrn, box, NULL, &crtcbox);
311
312	/* Make sure the CRTC is valid and this is the real front buffer */
313	if (crtc != NULL && !crtc->rotatedData) {
314	    pipe = i830_crtc_to_pipe(crtc);
315
316	    if (pipe == 0) {
317		event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
318		load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
319	    } else {
320		event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
321		load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
322	    }
323
324	    /* Make sure we don't wait for a scanline that will never occur */
325	    y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0;
326	    y2 = (box->y2 <= crtcbox.y2) ?
327		box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1;
328
329	    BEGIN_BATCH(5);
330	    /* The documentation says that the LOAD_SCAN_LINES command
331	     * always comes in pairs. Don't ask me why. */
332	    OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe);
333	    OUT_BATCH((y1 << 16) | y2);
334	    OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe);
335	    OUT_BATCH((y1 << 16) | y2);
336	    OUT_BATCH(MI_WAIT_FOR_EVENT | event);
337	    ADVANCE_BATCH();
338	}
339    }
340
341    (*pGC->ops->CopyArea)(src, dst,
342			  pGC, 0, 0, pDraw->width, pDraw->height, 0, 0);
343    FreeScratchGC(pGC);
344
345    /* Emit a flush of the rendering cache, or on the 965 and beyond
346     * rendering results may not hit the framebuffer until significantly
347     * later.
348     */
349    I830EmitFlush(pScrn);
350    pI830->need_mi_flush = FALSE;
351
352    /* We can't rely on getting into the block handler before the DRI
353     * client gets to run again so flush now. */
354    intel_batch_flush(pScrn, TRUE);
355#if ALWAYS_SYNC
356    I830Sync(pScrn);
357#endif
358    drmCommandNone(pI830->drmSubFD, DRM_I915_GEM_THROTTLE);
359
360}
361
362Bool I830DRI2ScreenInit(ScreenPtr pScreen)
363{
364    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
365    I830Ptr pI830 = I830PTR(pScrn);
366    DRI2InfoRec info;
367    char *p;
368    int i;
369    struct stat sbuf;
370    dev_t d;
371#ifdef USE_DRI2_1_1_0
372    int dri2_major = 1;
373    int dri2_minor = 0;
374#endif
375
376#ifdef USE_DRI2_1_1_0
377    if (xf86LoaderCheckSymbol("DRI2Version")) {
378	DRI2Version(& dri2_major, & dri2_minor);
379    }
380
381    if (dri2_minor < 1) {
382	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
383		   "DRI2 requires DRI2 module version 1.1.0 or later\n");
384	return FALSE;
385    }
386#endif
387
388    info.fd = pI830->drmSubFD;
389
390    /* The whole drmOpen thing is a fiasco and we need to find a way
391     * back to just using open(2).  For now, however, lets just make
392     * things worse with even more ad hoc directory walking code to
393     * discover the device file name. */
394
395    fstat(info.fd, &sbuf);
396    d = sbuf.st_rdev;
397
398    p = pI830->deviceName;
399    for (i = 0; i < DRM_MAX_MINOR; i++) {
400	sprintf(p, DRM_DEV_NAME, DRM_DIR_NAME, i);
401	if (stat(p, &sbuf) == 0 && sbuf.st_rdev == d)
402	    break;
403    }
404    if (i == DRM_MAX_MINOR) {
405	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
406		   "DRI2: failed to open drm device\n");
407	return FALSE;
408    }
409
410    info.driverName = IS_I965G(pI830) ? "i965" : "i915";
411    info.deviceName = p;
412
413#if DRI2INFOREC_VERSION >= 3
414    info.version = 3;
415    info.CreateBuffer = I830DRI2CreateBuffer;
416    info.DestroyBuffer = I830DRI2DestroyBuffer;
417#else
418# ifdef USE_DRI2_1_1_0
419    info.version = 2;
420    info.CreateBuffers = NULL;
421    info.DestroyBuffers = NULL;
422    info.CreateBuffer = I830DRI2CreateBuffer;
423    info.DestroyBuffer = I830DRI2DestroyBuffer;
424# else
425    info.version = 1;
426    info.CreateBuffers = I830DRI2CreateBuffers;
427    info.DestroyBuffers = I830DRI2DestroyBuffers;
428# endif
429#endif
430
431    info.CopyRegion = I830DRI2CopyRegion;
432
433    return DRI2ScreenInit(pScreen, &info);
434}
435
436void I830DRI2CloseScreen(ScreenPtr pScreen)
437{
438    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
439    I830Ptr pI830 = I830PTR(pScrn);
440
441    DRI2CloseScreen(pScreen);
442    pI830->directRenderingType = DRI_NONE;
443}
444