Imported Upstream version 1.11.4
[ubuntu-omap:xserver.git] / hw / xfree86 / dri2 / dri2.c
1 /*
2  * Copyright © 2007, 2008 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Soft-
6  * ware"), to deal in the Software without restriction, including without
7  * limitation the rights to use, copy, modify, merge, publish, distribute,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, provided that the above copyright
10  * notice(s) and this permission notice appear in all copies of the Soft-
11  * ware and that both the above copyright notice(s) and this permission
12  * notice appear in supporting documentation.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22  * MANCE OF THIS SOFTWARE.
23  *
24  * Except as contained in this notice, the name of a copyright holder shall
25  * not be used in advertising or otherwise to promote the sale, use or
26  * other dealings in this Software without prior written authorization of
27  * the copyright holder.
28  *
29  * Authors:
30  *   Kristian Høgsberg (krh@redhat.com)
31  */
32
33 #ifdef HAVE_XORG_CONFIG_H
34 #include <xorg-config.h>
35 #endif
36
37 #include <errno.h>
38 #ifdef WITH_LIBDRM
39 #include <xf86drm.h>
40 #endif
41 #include "xf86Module.h"
42 #include "list.h"
43 #include "scrnintstr.h"
44 #include "windowstr.h"
45 #include "dixstruct.h"
46 #include "dri2.h"
47 #include "xf86VGAarbiter.h"
48
49 #include "xf86.h"
50
51 CARD8 dri2_major; /* version of DRI2 supported by DDX */
52 CARD8 dri2_minor;
53
54 static DevPrivateKeyRec dri2ScreenPrivateKeyRec;
55 #define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
56
57 static DevPrivateKeyRec dri2WindowPrivateKeyRec;
58 #define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
59
60 static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
61 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
62
63 static RESTYPE       dri2DrawableRes;
64
65 typedef struct _DRI2Screen *DRI2ScreenPtr;
66
67 typedef struct _DRI2Drawable {
68     DRI2ScreenPtr        dri2_screen;
69     DrawablePtr          drawable;
70     struct list          reference_list;
71     int                  width;
72     int                  height;
73     DRI2BufferPtr       *buffers;
74     int                  bufferCount;
75     unsigned int         swapsPending;
76     ClientPtr            blockedClient;
77     Bool                 blockedOnMsc;
78     int                  swap_interval;
79     CARD64               swap_count;
80     int64_t              target_sbc; /* -1 means no SBC wait outstanding */
81     CARD64               last_swap_target; /* most recently queued swap target */
82     CARD64               last_swap_msc; /* msc at completion of most recent swap */
83     CARD64               last_swap_ust; /* ust at completion of most recent swap */
84     int                  swap_limit; /* for N-buffering */
85     unsigned long        serialNumber;
86     Bool                 needInvalidate;
87 } DRI2DrawableRec, *DRI2DrawablePtr;
88
89 typedef struct _DRI2Screen {
90     ScreenPtr                    screen;
91     int                          refcnt;
92     unsigned int                 numDrivers;
93     const char                  **driverNames;
94     const char                  *deviceName;
95     int                          fd;
96     unsigned int                 lastSequence;
97
98     DRI2CreateBufferProcPtr      CreateBuffer;
99     DRI2DestroyBufferProcPtr     DestroyBuffer;
100     DRI2CopyRegionProcPtr        CopyRegion;
101     DRI2ScheduleSwapProcPtr      ScheduleSwap;
102     DRI2GetMSCProcPtr            GetMSC;
103     DRI2ScheduleWaitMSCProcPtr   ScheduleWaitMSC;
104     DRI2AuthMagicProcPtr         AuthMagic;
105
106     HandleExposuresProcPtr       HandleExposures;
107
108     ConfigNotifyProcPtr          ConfigNotify;
109 } DRI2ScreenRec;
110
111 static DRI2ScreenPtr
112 DRI2GetScreen(ScreenPtr pScreen)
113 {
114     return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
115 }
116
117 static DRI2DrawablePtr
118 DRI2GetDrawable(DrawablePtr pDraw)
119 {
120     WindowPtr pWin;
121     PixmapPtr pPixmap;
122
123     switch (pDraw->type) {
124     case DRAWABLE_WINDOW:
125         pWin = (WindowPtr) pDraw;
126         return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey);
127     case DRAWABLE_PIXMAP:
128         pPixmap = (PixmapPtr) pDraw;
129         return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey);
130     default:
131         return NULL;
132     }
133 }
134
135 static unsigned long
136 DRI2DrawableSerial(DrawablePtr pDraw)
137 {
138     ScreenPtr pScreen = pDraw->pScreen;
139     PixmapPtr pPix;
140
141     if (pDraw->type != DRAWABLE_WINDOW)
142         return pDraw->serialNumber;
143
144     pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
145     return pPix->drawable.serialNumber;
146 }
147
148 static DRI2DrawablePtr
149 DRI2AllocateDrawable(DrawablePtr pDraw)
150 {
151     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
152     DRI2DrawablePtr pPriv;
153     CARD64          ust;
154     WindowPtr pWin;
155     PixmapPtr pPixmap;
156
157     pPriv = malloc(sizeof *pPriv);
158     if (pPriv == NULL)
159         return NULL;
160
161     pPriv->dri2_screen = ds;
162     pPriv->drawable = pDraw;
163     pPriv->width = pDraw->width;
164     pPriv->height = pDraw->height;
165     pPriv->buffers = NULL;
166     pPriv->bufferCount = 0;
167     pPriv->swapsPending = 0;
168     pPriv->blockedClient = NULL;
169     pPriv->blockedOnMsc = FALSE;
170     pPriv->swap_count = 0;
171     pPriv->target_sbc = -1;
172     pPriv->swap_interval = 1;
173     /* Initialize last swap target from DDX if possible */
174     if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target))
175         pPriv->last_swap_target = 0;
176
177     pPriv->swap_limit = 1; /* default to double buffering */
178     pPriv->last_swap_msc = 0;
179     pPriv->last_swap_ust = 0;
180     list_init(&pPriv->reference_list);
181     pPriv->serialNumber = DRI2DrawableSerial(pDraw);
182
183     if (pDraw->type == DRAWABLE_WINDOW) {
184         pWin = (WindowPtr) pDraw;
185         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
186     } else {
187         pPixmap = (PixmapPtr) pDraw;
188         dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
189     }
190
191     return pPriv;
192 }
193
194 typedef struct DRI2DrawableRefRec {
195     XID           id;
196     XID           dri2_id;
197     DRI2InvalidateProcPtr       invalidate;
198     void         *priv;
199     struct list   link;
200 } DRI2DrawableRefRec, *DRI2DrawableRefPtr;
201
202 static DRI2DrawableRefPtr
203 DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
204 {
205     DRI2DrawableRefPtr ref;
206
207     list_for_each_entry(ref, &pPriv->reference_list, link) {
208         if (ref->id == id)
209             return ref;
210     }
211     
212     return NULL;
213 }
214
215 static int
216 DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
217                    DRI2InvalidateProcPtr invalidate, void *priv)
218 {
219     DRI2DrawableRefPtr ref;
220
221     ref = malloc(sizeof *ref);
222     if (ref == NULL)
223         return BadAlloc;
224         
225     if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) {
226         free(ref);
227         return BadAlloc;
228     }
229     if (!DRI2LookupDrawableRef(pPriv, id))
230         if (!AddResource(id, dri2DrawableRes, pPriv)) {
231             FreeResourceByType(dri2_id, dri2DrawableRes, TRUE);
232             free(ref);
233             return BadAlloc;
234         }
235
236     ref->id = id;
237     ref->dri2_id = dri2_id; 
238     ref->invalidate = invalidate;
239     ref->priv = priv;
240     list_add(&ref->link, &pPriv->reference_list);
241
242     return Success;
243 }
244
245 int
246 DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
247                    DRI2InvalidateProcPtr invalidate, void *priv)
248 {
249     DRI2DrawablePtr pPriv;
250     XID dri2_id;
251     int rc;
252
253     pPriv = DRI2GetDrawable(pDraw);
254     if (pPriv == NULL)
255         pPriv = DRI2AllocateDrawable(pDraw);
256     if (pPriv == NULL)
257         return BadAlloc;
258     
259     dri2_id = FakeClientID(client->index);
260     rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
261     if (rc != Success)
262         return rc;
263
264     return Success;
265 }
266
267 static int DRI2DrawableGone(pointer p, XID id)
268 {
269     DRI2DrawablePtr pPriv = p;
270     DRI2ScreenPtr   ds = pPriv->dri2_screen;
271     DRI2DrawableRefPtr ref, next;
272     WindowPtr pWin;
273     PixmapPtr pPixmap;
274     DrawablePtr pDraw;
275     int i;
276
277     list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
278         if (ref->dri2_id == id) {
279             list_del(&ref->link);
280             /* If this was the last ref under this X drawable XID,
281              * unregister the X drawable resource. */
282             if (!DRI2LookupDrawableRef(pPriv, ref->id))
283                 FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
284             free(ref);
285             break;
286         }
287
288         if (ref->id == id) {
289             list_del(&ref->link);
290             FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
291             free(ref);
292         }
293     }
294
295     if (!list_is_empty(&pPriv->reference_list))
296         return Success;
297
298     pDraw = pPriv->drawable;
299     if (pDraw->type == DRAWABLE_WINDOW) {
300         pWin = (WindowPtr) pDraw;
301         dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
302     } else {
303         pPixmap = (PixmapPtr) pDraw;
304         dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
305     }
306
307     if (pPriv->buffers != NULL) {
308         for (i = 0; i < pPriv->bufferCount; i++)
309             (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
310
311         free(pPriv->buffers);
312     }
313
314     free(pPriv);
315
316     return Success;
317 }
318
319 static int
320 find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
321 {
322     int i;
323
324     if (pPriv->buffers == NULL) {
325         return -1;
326     }
327
328     for (i = 0; i < pPriv->bufferCount; i++) {
329         if ((pPriv->buffers[i] != NULL)
330             && (pPriv->buffers[i]->attachment == attachment)) {
331             return i;
332         }
333     }
334
335     return -1;
336 }
337
338 static Bool
339 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
340                          DRI2DrawablePtr pPriv,
341                          unsigned int attachment, unsigned int format,
342                          int dimensions_match, DRI2BufferPtr *buffer)
343 {
344     int old_buf = find_attachment(pPriv, attachment);
345
346     if ((old_buf < 0)
347         || !dimensions_match
348         || (pPriv->buffers[old_buf]->format != format)) {
349         *buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
350         pPriv->serialNumber = DRI2DrawableSerial(pDraw);
351         return TRUE;
352
353     } else {
354         *buffer = pPriv->buffers[old_buf];
355         pPriv->buffers[old_buf] = NULL;
356         return FALSE;
357     }
358 }
359
360 static void
361 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
362                              DRI2BufferPtr *buffers, int out_count, int *width, int *height)
363 {
364     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
365     int i;
366
367     if (pPriv->buffers != NULL) {
368         for (i = 0; i < pPriv->bufferCount; i++) {
369             if (pPriv->buffers[i] != NULL) {
370                 (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
371             }
372         }
373
374         free(pPriv->buffers);
375     }
376
377     pPriv->buffers = buffers;
378     pPriv->bufferCount = out_count;
379     pPriv->width = pDraw->width;
380     pPriv->height = pDraw->height;
381     *width = pPriv->width;
382     *height = pPriv->height;
383 }
384
385 static DRI2BufferPtr *
386 do_get_buffers(DrawablePtr pDraw, int *width, int *height,
387                unsigned int *attachments, int count, int *out_count,
388                int has_format)
389 {
390     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
391     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
392     DRI2BufferPtr  *buffers;
393     int need_real_front = 0;
394     int need_fake_front = 0;
395     int have_fake_front = 0;
396     int front_format = 0;
397     int dimensions_match;
398     int buffers_changed = 0;
399     int i;
400
401     if (!pPriv) {
402         *width = pDraw->width;
403         *height = pDraw->height;
404         *out_count = 0;
405         return NULL;
406     }
407
408     dimensions_match = (pDraw->width == pPriv->width)
409         && (pDraw->height == pPriv->height)
410         && (pPriv->serialNumber == DRI2DrawableSerial(pDraw));
411
412     buffers = calloc((count + 1), sizeof(buffers[0]));
413     if (!buffers)
414         goto err_out;
415
416     for (i = 0; i < count; i++) {
417         const unsigned attachment = *(attachments++);
418         const unsigned format = (has_format) ? *(attachments++) : 0;
419
420         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
421                                      format, dimensions_match,
422                                      &buffers[i]))
423                 buffers_changed = 1;
424
425         if (buffers[i] == NULL)
426             goto err_out;
427
428         /* If the drawable is a window and the front-buffer is requested,
429          * silently add the fake front-buffer to the list of requested
430          * attachments.  The counting logic in the loop accounts for the case
431          * where the client requests both the fake and real front-buffer.
432          */
433         if (attachment == DRI2BufferBackLeft) {
434             need_real_front++;
435             front_format = format;
436         }
437
438         if (attachment == DRI2BufferFrontLeft) {
439             need_real_front--;
440             front_format = format;
441
442             if (pDraw->type == DRAWABLE_WINDOW) {
443                 need_fake_front++;
444             }
445         }
446
447         if (pDraw->type == DRAWABLE_WINDOW) {
448             if (attachment == DRI2BufferFakeFrontLeft) {
449                 need_fake_front--;
450                 have_fake_front = 1;
451             }
452         }
453     }
454
455     if (need_real_front > 0) {
456         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
457                                      front_format, dimensions_match,
458                                      &buffers[i]))
459             buffers_changed = 1;
460
461         if (buffers[i] == NULL)
462             goto err_out;
463         i++;
464     }
465
466     if (need_fake_front > 0) {
467         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
468                                      front_format, dimensions_match,
469                                      &buffers[i]))
470             buffers_changed = 1;
471
472         if (buffers[i] == NULL)
473             goto err_out;
474
475         i++;
476         have_fake_front = 1;
477     }
478
479     *out_count = i;
480
481     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height);
482
483     /* If the client is getting a fake front-buffer, pre-fill it with the
484      * contents of the real front-buffer.  This ensures correct operation of
485      * applications that call glXWaitX before calling glDrawBuffer.
486      */
487     if (have_fake_front && buffers_changed) {
488         BoxRec box;
489         RegionRec region;
490
491         box.x1 = 0;
492         box.y1 = 0;
493         box.x2 = pPriv->width;
494         box.y2 = pPriv->height;
495         RegionInit(&region, &box, 0);
496
497         DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
498                        DRI2BufferFrontLeft);
499     }
500
501     pPriv->needInvalidate = TRUE;
502
503     return pPriv->buffers;
504
505 err_out:
506
507     *out_count = 0;
508
509     if (buffers) {
510         for (i = 0; i < count; i++) {
511             if (buffers[i] != NULL)
512                 (*ds->DestroyBuffer)(pDraw, buffers[i]);
513         }
514
515         free(buffers);
516         buffers = NULL;
517     }
518
519     update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height);
520
521     return buffers;
522 }
523
524 DRI2BufferPtr *
525 DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
526                unsigned int *attachments, int count, int *out_count)
527 {
528     return do_get_buffers(pDraw, width, height, attachments, count,
529                           out_count, FALSE);
530 }
531
532 DRI2BufferPtr *
533 DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
534                          unsigned int *attachments, int count, int *out_count)
535 {
536     return do_get_buffers(pDraw, width, height, attachments, count,
537                           out_count, TRUE);
538 }
539
540 static void
541 DRI2InvalidateDrawable(DrawablePtr pDraw)
542 {
543     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
544     DRI2DrawableRefPtr ref;
545
546     if (!pPriv || !pPriv->needInvalidate)
547         return;
548
549     pPriv->needInvalidate = FALSE;
550
551     list_for_each_entry(ref, &pPriv->reference_list, link)
552         ref->invalidate(pDraw, ref->priv);
553 }
554
555 /*
556  * In the direct rendered case, we throttle the clients that have more
557  * than their share of outstanding swaps (and thus busy buffers) when a
558  * new GetBuffers request is received.  In the AIGLX case, we allow the
559  * client to get the new buffers, but throttle when the next GLX request
560  * comes in (see __glXDRIcontextWait()).
561  */
562 Bool
563 DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
564 {
565     DRI2DrawablePtr pPriv;
566
567     pPriv = DRI2GetDrawable(pDraw);
568     if (pPriv == NULL)
569         return FALSE;
570
571     /* Throttle to swap limit */
572     if ((pPriv->swapsPending >= pPriv->swap_limit) &&
573         !pPriv->blockedClient) {
574         ResetCurrentRequest(client);
575         client->sequence--;
576         IgnoreClient(client);
577         pPriv->blockedClient = client;
578         return TRUE;
579     }
580
581     return FALSE;
582 }
583
584 static void
585 __DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv)
586 {
587     if (pPriv->blockedClient == NULL) {
588         IgnoreClient(client);
589         pPriv->blockedClient = client;
590     }
591 }
592
593 void
594 DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
595 {
596     DRI2DrawablePtr pPriv;
597
598     pPriv = DRI2GetDrawable(pDraw);
599     if (pPriv == NULL)
600         return;
601
602     __DRI2BlockClient(client, pPriv);
603     pPriv->blockedOnMsc = TRUE;
604 }
605
606 int
607 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
608                unsigned int dest, unsigned int src)
609 {
610     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
611     DRI2DrawablePtr pPriv;
612     DRI2BufferPtr   pDestBuffer, pSrcBuffer;
613     int             i;
614
615     pPriv = DRI2GetDrawable(pDraw);
616     if (pPriv == NULL)
617         return BadDrawable;
618
619     pDestBuffer = NULL;
620     pSrcBuffer = NULL;
621     for (i = 0; i < pPriv->bufferCount; i++)
622     {
623         if (pPriv->buffers[i]->attachment == dest)
624             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
625         if (pPriv->buffers[i]->attachment == src)
626             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
627     }
628     if (pSrcBuffer == NULL || pDestBuffer == NULL)
629         return BadValue;
630
631     (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer);
632
633     return Success;
634 }
635
636 /* Can this drawable be page flipped? */
637 Bool
638 DRI2CanFlip(DrawablePtr pDraw)
639 {
640     ScreenPtr pScreen = pDraw->pScreen;
641     WindowPtr pWin, pRoot;
642     PixmapPtr pWinPixmap, pRootPixmap;
643
644     if (pDraw->type == DRAWABLE_PIXMAP)
645         return TRUE;
646
647     pRoot = pScreen->root;
648     pRootPixmap = pScreen->GetWindowPixmap(pRoot);
649
650     pWin = (WindowPtr) pDraw;
651     pWinPixmap = pScreen->GetWindowPixmap(pWin);
652     if (pRootPixmap != pWinPixmap)
653         return FALSE;
654     if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
655         return FALSE;
656
657     /* Does the window match the pixmap exactly? */
658     if (pDraw->x != 0 ||
659         pDraw->y != 0 ||
660 #ifdef COMPOSITE
661         pDraw->x != pWinPixmap->screen_x ||
662         pDraw->y != pWinPixmap->screen_y ||
663 #endif
664         pDraw->width != pWinPixmap->drawable.width ||
665         pDraw->height != pWinPixmap->drawable.height)
666         return FALSE;
667
668     return TRUE;
669 }
670
671 /* Can we do a pixmap exchange instead of a blit? */
672 Bool
673 DRI2CanExchange(DrawablePtr pDraw)
674 {
675     return FALSE;
676 }
677
678 void
679 DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
680                     unsigned int tv_sec, unsigned int tv_usec)
681 {
682     DRI2DrawablePtr pPriv;
683
684     pPriv = DRI2GetDrawable(pDraw);
685     if (pPriv == NULL)
686         return;
687
688     ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
689                          frame, pPriv->swap_count);
690
691     if (pPriv->blockedClient)
692         AttendClient(pPriv->blockedClient);
693
694     pPriv->blockedClient = NULL;
695     pPriv->blockedOnMsc = FALSE;
696 }
697
698 static void
699 DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
700                unsigned int tv_sec, unsigned int tv_usec)
701 {
702     ScreenPtr       pScreen = pDraw->pScreen;
703     DRI2DrawablePtr pPriv;
704
705     pPriv = DRI2GetDrawable(pDraw);
706     if (pPriv == NULL) {
707         xf86DrvMsg(pScreen->myNum, X_ERROR,
708                    "[DRI2] %s: bad drawable\n", __func__);
709         return;
710     }
711
712     /*
713      * Swap completed.
714      * Wake the client iff:
715      *   - it was waiting on SBC
716      *   - was blocked due to GLX make current
717      *   - was blocked due to swap throttling
718      *   - is not blocked due to an MSC wait
719      */
720     if (pPriv->target_sbc != -1 &&
721         pPriv->target_sbc <= pPriv->swap_count) {
722         ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
723                              frame, pPriv->swap_count);
724         pPriv->target_sbc = -1;
725
726         AttendClient(pPriv->blockedClient);
727         pPriv->blockedClient = NULL;
728     } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) {
729         if (pPriv->blockedClient) {
730             AttendClient(pPriv->blockedClient);
731             pPriv->blockedClient = NULL;
732         }
733     }
734 }
735
736 void
737 DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
738                    unsigned int tv_sec, unsigned int tv_usec, int type,
739                    DRI2SwapEventPtr swap_complete, void *swap_data)
740 {
741     ScreenPtr       pScreen = pDraw->pScreen;
742     DRI2DrawablePtr pPriv;
743     CARD64          ust = 0;
744     BoxRec          box;
745     RegionRec       region;
746
747     pPriv = DRI2GetDrawable(pDraw);
748     if (pPriv == NULL) {
749         xf86DrvMsg(pScreen->myNum, X_ERROR,
750                    "[DRI2] %s: bad drawable\n", __func__);
751         return;
752     }
753
754     pPriv->swapsPending--;
755     pPriv->swap_count++;
756
757     box.x1 = 0;
758     box.y1 = 0;
759     box.x2 = pDraw->width;
760     box.y2 = pDraw->height;
761     RegionInit(&region, &box, 0);
762     DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
763                    DRI2BufferFrontLeft);
764
765     ust = ((CARD64)tv_sec * 1000000) + tv_usec;
766     if (swap_complete)
767         swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
768
769     pPriv->last_swap_msc = frame;
770     pPriv->last_swap_ust = ust;
771
772     DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
773 }
774
775 Bool
776 DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
777 {
778     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
779
780     /* If we're currently waiting for a swap on this drawable, reset
781      * the request and suspend the client.  We only support one
782      * blocked client per drawable. */
783     if (pPriv &&
784         pPriv->swapsPending &&
785         pPriv->blockedClient == NULL) {
786         ResetCurrentRequest(client);
787         client->sequence--;
788         __DRI2BlockClient(client, pPriv);
789         return TRUE;
790     }
791
792     return FALSE;
793 }
794
795 int
796 DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
797                 CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
798                 DRI2SwapEventPtr func, void *data)
799 {
800     ScreenPtr       pScreen = pDraw->pScreen;
801     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
802     DRI2DrawablePtr pPriv;
803     DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL;
804     int             ret, i;
805     CARD64          ust, current_msc;
806
807     pPriv = DRI2GetDrawable(pDraw);
808     if (pPriv == NULL) {
809         xf86DrvMsg(pScreen->myNum, X_ERROR,
810                    "[DRI2] %s: bad drawable\n", __func__);
811         return BadDrawable;
812     }
813
814     for (i = 0; i < pPriv->bufferCount; i++) {
815         if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
816             pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
817         if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
818             pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
819     }
820     if (pSrcBuffer == NULL || pDestBuffer == NULL) {
821         xf86DrvMsg(pScreen->myNum, X_ERROR,
822                    "[DRI2] %s: drawable has no back or front?\n", __func__);
823         return BadDrawable;
824     }
825
826     /* Old DDX or no swap interval, just blit */
827     if (!ds->ScheduleSwap || !pPriv->swap_interval) {
828         BoxRec box;
829         RegionRec region;
830
831         box.x1 = 0;
832         box.y1 = 0;
833         box.x2 = pDraw->width;
834         box.y2 = pDraw->height;
835         RegionInit(&region, &box, 0);
836
837         pPriv->swapsPending++;
838
839         (*ds->CopyRegion)(pDraw, &region, pDestBuffer, pSrcBuffer);
840         DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
841                          func, data);
842         return Success;
843     }
844
845     /*
846      * In the simple glXSwapBuffers case, all params will be 0, and we just
847      * need to schedule a swap for the last swap target + the swap interval.
848      */
849     if (target_msc == 0 && divisor == 0 && remainder == 0) {
850         /* If the current vblank count of the drawable's crtc is lower
851          * than the count stored in last_swap_target from a previous swap
852          * then reinitialize last_swap_target to the current crtc's msc,
853          * otherwise the swap will hang. This will happen if the drawable
854          * is moved to a crtc with a lower refresh rate, or a crtc that just
855          * got enabled.
856          */
857         if (ds->GetMSC) {
858             if (!(*ds->GetMSC)(pDraw, &ust, &current_msc))
859                 pPriv->last_swap_target = 0;
860
861             if (current_msc < pPriv->last_swap_target)
862                 pPriv->last_swap_target = current_msc;
863
864         }
865
866         /*
867          * Swap target for this swap is last swap target + swap interval since
868          * we have to account for the current swap count, interval, and the
869          * number of pending swaps.
870          */
871         *swap_target = pPriv->last_swap_target + pPriv->swap_interval;
872
873     } else {
874         /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */
875         *swap_target = target_msc;
876     }
877
878     pPriv->swapsPending++;
879     ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
880                               swap_target, divisor, remainder, func, data);
881     if (!ret) {
882         pPriv->swapsPending--; /* didn't schedule */
883         xf86DrvMsg(pScreen->myNum, X_ERROR,
884                    "[DRI2] %s: driver failed to schedule swap\n", __func__);
885         return BadDrawable;
886     }
887
888     pPriv->last_swap_target = *swap_target;
889
890     /* According to spec, return expected swapbuffers count SBC after this swap
891      * will complete.
892      */
893     *swap_target = pPriv->swap_count + pPriv->swapsPending;
894
895     DRI2InvalidateDrawable(pDraw);
896
897     return Success;
898 }
899
900 void
901 DRI2SwapInterval(DrawablePtr pDrawable, int interval)
902 {
903     ScreenPtr       pScreen = pDrawable->pScreen;
904     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
905
906     if (pPriv == NULL) {
907         xf86DrvMsg(pScreen->myNum, X_ERROR,
908                    "[DRI2] %s: bad drawable\n", __func__);
909         return;
910     }
911
912     /* fixme: check against arbitrary max? */
913     pPriv->swap_interval = interval;
914 }
915
916 int
917 DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
918 {
919     ScreenPtr pScreen = pDraw->pScreen;
920     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
921     DRI2DrawablePtr pPriv;
922     Bool ret;
923
924     pPriv = DRI2GetDrawable(pDraw);
925     if (pPriv == NULL) {
926         xf86DrvMsg(pScreen->myNum, X_ERROR,
927                    "[DRI2] %s: bad drawable\n", __func__);
928         return BadDrawable;
929     }
930
931     if (!ds->GetMSC) {
932         *ust = 0;
933         *msc = 0;
934         *sbc = pPriv->swap_count;
935         return Success;
936     }
937
938     /*
939      * Spec needs to be updated to include unmapped or redirected
940      * drawables
941      */
942
943     ret = (*ds->GetMSC)(pDraw, ust, msc);
944     if (!ret)
945         return BadDrawable;
946
947     *sbc = pPriv->swap_count;
948
949     return Success;
950 }
951
952 int
953 DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
954             CARD64 divisor, CARD64 remainder)
955 {
956     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
957     DRI2DrawablePtr pPriv;
958     Bool ret;
959
960     pPriv = DRI2GetDrawable(pDraw);
961     if (pPriv == NULL)
962         return BadDrawable;
963
964     /* Old DDX just completes immediately */
965     if (!ds->ScheduleWaitMSC) {
966         DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
967
968         return Success;
969     }
970
971     ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder);
972     if (!ret)
973         return BadDrawable;
974
975     return Success;
976 }
977
978 int
979 DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
980 {
981     DRI2DrawablePtr pPriv;
982
983     pPriv = DRI2GetDrawable(pDraw);
984     if (pPriv == NULL)
985         return BadDrawable;
986
987     /* target_sbc == 0 means to block until all pending swaps are
988      * finished. Recalculate target_sbc to get that behaviour.
989      */
990     if (target_sbc == 0)
991         target_sbc = pPriv->swap_count + pPriv->swapsPending;
992
993     /* If current swap count already >= target_sbc, reply and
994      * return immediately with (ust, msc, sbc) triplet of
995      * most recent completed swap.
996      */
997     if (pPriv->swap_count >= target_sbc) {
998         ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
999                              pPriv->last_swap_msc, pPriv->swap_count);
1000         return Success;
1001     }
1002
1003     pPriv->target_sbc = target_sbc;
1004     __DRI2BlockClient(client, pPriv);
1005
1006     return Success;
1007 }
1008
1009 Bool
1010 DRI2HasSwapControl(ScreenPtr pScreen)
1011 {
1012     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1013
1014     return ds->ScheduleSwap && ds->GetMSC;
1015 }
1016
1017 Bool
1018 DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
1019             const char **driverName, const char **deviceName)
1020 {
1021     DRI2ScreenPtr ds;
1022
1023     if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
1024         return FALSE;
1025
1026     ds = DRI2GetScreen(pScreen);
1027     if (ds == NULL || driverType >= ds->numDrivers ||
1028             !ds->driverNames[driverType])
1029         return FALSE;
1030
1031     *fd = ds->fd;
1032     *driverName = ds->driverNames[driverType];
1033     *deviceName = ds->deviceName;
1034
1035     return TRUE;
1036 }
1037
1038 Bool
1039 DRI2Authenticate(ScreenPtr pScreen, uint32_t magic)
1040 {
1041     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1042
1043     if (ds == NULL || (*ds->AuthMagic)(ds->fd, magic))
1044         return FALSE;
1045
1046     return TRUE;
1047 }
1048
1049 static int
1050 DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
1051                  WindowPtr pSib)
1052 {
1053     DrawablePtr pDraw = (DrawablePtr)pWin;
1054     ScreenPtr pScreen = pDraw->pScreen;
1055     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1056     DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
1057     int ret;
1058
1059     if (ds->ConfigNotify) {
1060         pScreen->ConfigNotify = ds->ConfigNotify;
1061
1062         ret = (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib);
1063
1064         ds->ConfigNotify = pScreen->ConfigNotify;
1065         pScreen->ConfigNotify = DRI2ConfigNotify;
1066         if (ret)
1067             return ret;
1068     }
1069
1070     if (!dd || (dd->width == w && dd->height == h))
1071         return Success;
1072
1073     DRI2InvalidateDrawable(pDraw);
1074     return Success;
1075 }
1076
1077 Bool
1078 DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
1079 {
1080     DRI2ScreenPtr ds;
1081     const char* driverTypeNames[] = {
1082         "DRI", /* DRI2DriverDRI */
1083         "VDPAU", /* DRI2DriverVDPAU */
1084     };
1085     unsigned int i;
1086     CARD8 cur_minor;
1087
1088     if (info->version < 3)
1089         return FALSE;
1090
1091     if (!xf86VGAarbiterAllowDRI(pScreen)) {
1092         xf86DrvMsg(pScreen->myNum, X_WARNING,
1093                   "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n");
1094         return FALSE;
1095     }
1096
1097     if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1098         return FALSE;
1099
1100     if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
1101         return FALSE;
1102
1103     if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
1104         return FALSE;
1105
1106     ds = calloc(1, sizeof *ds);
1107     if (!ds)
1108         return FALSE;
1109
1110     ds->screen         = pScreen;
1111     ds->fd             = info->fd;
1112     ds->deviceName     = info->deviceName;
1113     dri2_major         = 1;
1114
1115     ds->CreateBuffer   = info->CreateBuffer;
1116     ds->DestroyBuffer  = info->DestroyBuffer;
1117     ds->CopyRegion     = info->CopyRegion;
1118
1119     if (info->version >= 4) {
1120         ds->ScheduleSwap = info->ScheduleSwap;
1121         ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
1122         ds->GetMSC = info->GetMSC;
1123         cur_minor = 3;
1124     } else {
1125         cur_minor = 1;
1126     }
1127
1128     if (info->version >= 5) {
1129         ds->AuthMagic = info->AuthMagic;
1130     }
1131
1132     /*
1133      * if the driver doesn't provide an AuthMagic function or the info struct
1134      * version is too low, it relies on the old method (using libdrm) or fail
1135      */
1136     if (!ds->AuthMagic)
1137 #ifdef WITH_LIBDRM
1138         ds->AuthMagic = drmAuthMagic;
1139 #else
1140         goto err_out;
1141 #endif
1142
1143     /* Initialize minor if needed and set to minimum provied by DDX */
1144     if (!dri2_minor || dri2_minor > cur_minor)
1145         dri2_minor = cur_minor;
1146
1147     if (info->version == 3 || info->numDrivers == 0) {
1148         /* Driver too old: use the old-style driverName field */
1149         ds->numDrivers = 1;
1150         ds->driverNames = malloc(sizeof(*ds->driverNames));
1151         if (!ds->driverNames)
1152             goto err_out;
1153         ds->driverNames[0] = info->driverName;
1154     } else {
1155         ds->numDrivers = info->numDrivers;
1156         ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames));
1157         if (!ds->driverNames)
1158                 goto err_out;
1159         memcpy(ds->driverNames, info->driverNames,
1160                info->numDrivers * sizeof(*ds->driverNames));
1161     }
1162
1163     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
1164
1165     ds->ConfigNotify = pScreen->ConfigNotify;
1166     pScreen->ConfigNotify = DRI2ConfigNotify;
1167
1168     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
1169     for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) {
1170         if (i < ds->numDrivers && ds->driverNames[i]) {
1171             xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
1172                        driverTypeNames[i], ds->driverNames[i]);
1173         }
1174     }
1175
1176     return TRUE;
1177
1178 err_out:
1179     xf86DrvMsg(pScreen->myNum, X_WARNING,
1180             "[DRI2] Initialization failed for info version %d.\n", info->version);
1181     free(ds);
1182     return FALSE;
1183 }
1184
1185 void
1186 DRI2CloseScreen(ScreenPtr pScreen)
1187 {
1188     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1189     pScreen->ConfigNotify = ds->ConfigNotify;
1190
1191     free(ds->driverNames);
1192     free(ds);
1193     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
1194 }
1195
1196 extern ExtensionModule dri2ExtensionModule;
1197 extern Bool DRI2ModuleSetup(void);
1198
1199 /* Called by InitExtensions() */
1200 Bool
1201 DRI2ModuleSetup(void)
1202 {
1203     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
1204     if (!dri2DrawableRes)
1205         return FALSE;
1206
1207     return TRUE;
1208 }
1209
1210 static pointer
1211 DRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin)
1212 {
1213     static Bool setupDone = FALSE;
1214
1215     if (!setupDone)
1216     {
1217         setupDone = TRUE;
1218         LoadExtension(&dri2ExtensionModule, FALSE);
1219     }
1220     else
1221     {
1222         if (errmaj)
1223             *errmaj = LDR_ONCEONLY;
1224     }
1225
1226     return (pointer) 1;
1227 }
1228
1229 static XF86ModuleVersionInfo DRI2VersRec =
1230 {
1231     "dri2",
1232     MODULEVENDORSTRING,
1233     MODINFOSTRING1,
1234     MODINFOSTRING2,
1235     XORG_VERSION_CURRENT,
1236     1, 2, 0,
1237     ABI_CLASS_EXTENSION,
1238     ABI_EXTENSION_VERSION,
1239     MOD_CLASS_NONE,
1240     { 0, 0, 0, 0 }
1241 };
1242
1243 _X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL };
1244
1245 void
1246 DRI2Version(int *major, int *minor)
1247 {
1248     if (major != NULL)
1249         *major = DRI2VersRec.majorversion;
1250
1251     if (minor != NULL)
1252         *minor = DRI2VersRec.minorversion;
1253 }