dri2.c revision f7df2e56
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 "dri2int.h"
48#include "xf86VGAarbiter.h"
49#include "damage.h"
50#include "xf86.h"
51
52CARD8 dri2_major;               /* version of DRI2 supported by DDX */
53CARD8 dri2_minor;
54
55uint32_t prime_id_allocate_bitmask;
56
57static DevPrivateKeyRec dri2ScreenPrivateKeyRec;
58
59#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
60
61static DevPrivateKeyRec dri2WindowPrivateKeyRec;
62
63#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
64
65static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
66
67#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
68
69static DevPrivateKeyRec dri2ClientPrivateKeyRec;
70
71#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
72
73#define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \
74                                                      dri2ClientPrivateKey))
75
76typedef struct _DRI2Client {
77    int prime_id;
78} DRI2ClientRec, *DRI2ClientPtr;
79
80static RESTYPE dri2DrawableRes;
81
82typedef struct _DRI2Screen *DRI2ScreenPtr;
83
84typedef struct _DRI2Drawable {
85    DRI2ScreenPtr dri2_screen;
86    DrawablePtr drawable;
87    struct xorg_list reference_list;
88    int width;
89    int height;
90    DRI2BufferPtr *buffers;
91    int bufferCount;
92    unsigned int swapsPending;
93    int swap_interval;
94    CARD64 swap_count;
95    int64_t target_sbc;         /* -1 means no SBC wait outstanding */
96    CARD64 last_swap_target;    /* most recently queued swap target */
97    CARD64 last_swap_msc;       /* msc at completion of most recent swap */
98    CARD64 last_swap_ust;       /* ust at completion of most recent swap */
99    int swap_limit;             /* for N-buffering */
100    unsigned blocked[3];
101    Bool needInvalidate;
102    int prime_id;
103    PixmapPtr prime_slave_pixmap;
104    PixmapPtr redirectpixmap;
105} DRI2DrawableRec, *DRI2DrawablePtr;
106
107typedef struct _DRI2Screen {
108    ScreenPtr screen;
109    int refcnt;
110    unsigned int numDrivers;
111    const char **driverNames;
112    const char *deviceName;
113    int fd;
114    unsigned int lastSequence;
115    int prime_id;
116
117    DRI2CreateBufferProcPtr CreateBuffer;
118    DRI2DestroyBufferProcPtr DestroyBuffer;
119    DRI2CopyRegionProcPtr CopyRegion;
120    DRI2ScheduleSwapProcPtr ScheduleSwap;
121    DRI2GetMSCProcPtr GetMSC;
122    DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC;
123    DRI2AuthMagic2ProcPtr AuthMagic;
124    DRI2AuthMagicProcPtr LegacyAuthMagic;
125    DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
126    DRI2SwapLimitValidateProcPtr SwapLimitValidate;
127    DRI2GetParamProcPtr GetParam;
128
129    HandleExposuresProcPtr HandleExposures;
130
131    ConfigNotifyProcPtr ConfigNotify;
132    SetWindowPixmapProcPtr SetWindowPixmap;
133    DRI2CreateBuffer2ProcPtr CreateBuffer2;
134    DRI2DestroyBuffer2ProcPtr DestroyBuffer2;
135    DRI2CopyRegion2ProcPtr CopyRegion2;
136} DRI2ScreenRec;
137
138static void
139destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id);
140
141enum DRI2WakeType {
142    WAKE_SBC,
143    WAKE_MSC,
144    WAKE_SWAP,
145};
146
147#define Wake(c, t) (void *)((uintptr_t)(c) | (t))
148
149static Bool
150dri2WakeClient(ClientPtr client, void *closure)
151{
152    ClientWakeup(client);
153    return TRUE;
154}
155
156static Bool
157dri2WakeAll(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
158{
159    int count;
160
161    if (!pPriv->blocked[t])
162        return FALSE;
163
164    count = ClientSignalAll(client, dri2WakeClient, Wake(pPriv, t));
165    pPriv->blocked[t] -= count;
166    return count;
167}
168
169static Bool
170dri2Sleep(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
171{
172    if (ClientSleep(client, dri2WakeClient, Wake(pPriv, t))) {
173        pPriv->blocked[t]++;
174        return TRUE;
175    }
176    return FALSE;
177}
178
179static DRI2ScreenPtr
180DRI2GetScreen(ScreenPtr pScreen)
181{
182    return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
183}
184
185static ScreenPtr
186GetScreenPrime(ScreenPtr master, int prime_id)
187{
188    ScreenPtr slave;
189    if (prime_id == 0 || xorg_list_is_empty(&master->offload_slave_list)) {
190        return master;
191    }
192    xorg_list_for_each_entry(slave, &master->offload_slave_list, offload_head) {
193        DRI2ScreenPtr ds;
194
195        ds = DRI2GetScreen(slave);
196        if (ds == NULL)
197            continue;
198
199        if (ds->prime_id == prime_id)
200            return slave;
201    }
202    return master;
203}
204
205static DRI2ScreenPtr
206DRI2GetScreenPrime(ScreenPtr master, int prime_id)
207{
208    ScreenPtr slave = GetScreenPrime(master, prime_id);
209    return DRI2GetScreen(slave);
210}
211
212static DRI2DrawablePtr
213DRI2GetDrawable(DrawablePtr pDraw)
214{
215    WindowPtr pWin;
216    PixmapPtr pPixmap;
217
218    switch (pDraw->type) {
219    case DRAWABLE_WINDOW:
220        pWin = (WindowPtr) pDraw;
221        return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey);
222    case DRAWABLE_PIXMAP:
223        pPixmap = (PixmapPtr) pDraw;
224        return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey);
225    default:
226        return NULL;
227    }
228}
229
230static DRI2DrawablePtr
231DRI2AllocateDrawable(DrawablePtr pDraw)
232{
233    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
234    DRI2DrawablePtr pPriv;
235    CARD64 ust;
236    WindowPtr pWin;
237    PixmapPtr pPixmap;
238
239    pPriv = malloc(sizeof *pPriv);
240    if (pPriv == NULL)
241        return NULL;
242
243    pPriv->dri2_screen = ds;
244    pPriv->drawable = pDraw;
245    pPriv->width = pDraw->width;
246    pPriv->height = pDraw->height;
247    pPriv->buffers = NULL;
248    pPriv->bufferCount = 0;
249    pPriv->swapsPending = 0;
250    pPriv->swap_count = 0;
251    pPriv->target_sbc = -1;
252    pPriv->swap_interval = 1;
253    /* Initialize last swap target from DDX if possible */
254    if (!ds->GetMSC || !(*ds->GetMSC) (pDraw, &ust, &pPriv->last_swap_target))
255        pPriv->last_swap_target = 0;
256
257    memset(pPriv->blocked, 0, sizeof(pPriv->blocked));
258    pPriv->swap_limit = 1;      /* default to double buffering */
259    pPriv->last_swap_msc = 0;
260    pPriv->last_swap_ust = 0;
261    xorg_list_init(&pPriv->reference_list);
262    pPriv->needInvalidate = FALSE;
263    pPriv->redirectpixmap = NULL;
264    pPriv->prime_slave_pixmap = NULL;
265    if (pDraw->type == DRAWABLE_WINDOW) {
266        pWin = (WindowPtr) pDraw;
267        dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
268    }
269    else {
270        pPixmap = (PixmapPtr) pDraw;
271        dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
272    }
273
274    return pPriv;
275}
276
277Bool
278DRI2SwapLimit(DrawablePtr pDraw, int swap_limit)
279{
280    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
281    DRI2ScreenPtr ds;
282
283    if (!pPriv)
284        return FALSE;
285
286    ds = pPriv->dri2_screen;
287
288    if (!ds->SwapLimitValidate || !ds->SwapLimitValidate(pDraw, swap_limit))
289        return FALSE;
290
291    pPriv->swap_limit = swap_limit;
292
293    /* Check throttling */
294    if (pPriv->swapsPending >= pPriv->swap_limit)
295        return TRUE;
296
297    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
298    return TRUE;
299}
300
301typedef struct DRI2DrawableRefRec {
302    XID id;
303    XID dri2_id;
304    DRI2InvalidateProcPtr invalidate;
305    void *priv;
306    struct xorg_list link;
307} DRI2DrawableRefRec, *DRI2DrawableRefPtr;
308
309static DRI2DrawableRefPtr
310DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
311{
312    DRI2DrawableRefPtr ref = NULL;
313
314    xorg_list_for_each_entry(ref, &pPriv->reference_list, link) {
315        if (ref->id == id)
316            return ref;
317    }
318
319    return NULL;
320}
321
322static int
323DRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
324                   DRI2InvalidateProcPtr invalidate, void *priv)
325{
326    DRI2DrawableRefPtr ref;
327
328    ref = malloc(sizeof *ref);
329    if (ref == NULL)
330        return BadAlloc;
331
332    if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) {
333        free(ref);
334        return BadAlloc;
335    }
336    if (!DRI2LookupDrawableRef(pPriv, id))
337        if (!AddResource(id, dri2DrawableRes, pPriv)) {
338            FreeResourceByType(dri2_id, dri2DrawableRes, TRUE);
339            free(ref);
340            return BadAlloc;
341        }
342
343    ref->id = id;
344    ref->dri2_id = dri2_id;
345    ref->invalidate = invalidate;
346    ref->priv = priv;
347    xorg_list_add(&ref->link, &pPriv->reference_list);
348
349    return Success;
350}
351
352int
353DRI2CreateDrawable2(ClientPtr client, DrawablePtr pDraw, XID id,
354                    DRI2InvalidateProcPtr invalidate, void *priv,
355                    XID *dri2_id_out)
356{
357    DRI2DrawablePtr pPriv;
358    DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
359    XID dri2_id;
360    int rc;
361
362    pPriv = DRI2GetDrawable(pDraw);
363    if (pPriv == NULL)
364        pPriv = DRI2AllocateDrawable(pDraw);
365    if (pPriv == NULL)
366        return BadAlloc;
367
368    pPriv->prime_id = dri2_client->prime_id;
369
370    dri2_id = FakeClientID(client->index);
371    rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
372    if (rc != Success)
373        return rc;
374
375    if (dri2_id_out)
376        *dri2_id_out = dri2_id;
377
378    return Success;
379}
380
381int
382DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
383                   DRI2InvalidateProcPtr invalidate, void *priv)
384{
385    return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL);
386}
387
388static int
389DRI2DrawableGone(void *p, XID id)
390{
391    DRI2DrawablePtr pPriv = p;
392    DRI2DrawableRefPtr ref, next;
393    WindowPtr pWin;
394    PixmapPtr pPixmap;
395    DrawablePtr pDraw;
396    int i;
397
398    xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
399        if (ref->dri2_id == id) {
400            xorg_list_del(&ref->link);
401            /* If this was the last ref under this X drawable XID,
402             * unregister the X drawable resource. */
403            if (!DRI2LookupDrawableRef(pPriv, ref->id))
404                FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
405            free(ref);
406            break;
407        }
408
409        if (ref->id == id) {
410            xorg_list_del(&ref->link);
411            FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
412            free(ref);
413        }
414    }
415
416    if (!xorg_list_is_empty(&pPriv->reference_list))
417        return Success;
418
419    pDraw = pPriv->drawable;
420    if (pDraw->type == DRAWABLE_WINDOW) {
421        pWin = (WindowPtr) pDraw;
422        dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
423    }
424    else {
425        pPixmap = (PixmapPtr) pDraw;
426        dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
427    }
428
429    if (pPriv->prime_slave_pixmap) {
430        (*pPriv->prime_slave_pixmap->master_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_slave_pixmap->master_pixmap);
431        (*pPriv->prime_slave_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_slave_pixmap);
432    }
433
434    if (pPriv->buffers != NULL) {
435        for (i = 0; i < pPriv->bufferCount; i++)
436            destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
437
438        free(pPriv->buffers);
439    }
440
441    if (pPriv->redirectpixmap) {
442        (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
443        (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap);
444    }
445
446    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
447    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC);
448    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC);
449
450    free(pPriv);
451
452    return Success;
453}
454
455static DRI2BufferPtr
456create_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw,
457              unsigned int attachment, unsigned int format)
458{
459    DRI2BufferPtr buffer;
460    if (ds->CreateBuffer2)
461        buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen,
462                                                     DRI2GetDrawable(pDraw)->prime_id),
463                                      pDraw, attachment, format);
464    else
465        buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
466    return buffer;
467}
468
469static void
470destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id)
471{
472    ScreenPtr primeScreen;
473    DRI2ScreenPtr ds;
474    primeScreen = GetScreenPrime(pDraw->pScreen, prime_id);
475    ds = DRI2GetScreen(primeScreen);
476    if (ds->DestroyBuffer2)
477        (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer);
478    else
479        (*ds->DestroyBuffer)(pDraw, buffer);
480}
481
482static int
483find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
484{
485    int i;
486
487    if (pPriv->buffers == NULL) {
488        return -1;
489    }
490
491    for (i = 0; i < pPriv->bufferCount; i++) {
492        if ((pPriv->buffers[i] != NULL)
493            && (pPriv->buffers[i]->attachment == attachment)) {
494            return i;
495        }
496    }
497
498    return -1;
499}
500
501static Bool
502allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
503                         DRI2DrawablePtr pPriv,
504                         unsigned int attachment, unsigned int format,
505                         int dimensions_match, DRI2BufferPtr * buffer)
506{
507    int old_buf = find_attachment(pPriv, attachment);
508
509    if ((old_buf < 0)
510        || attachment == DRI2BufferFrontLeft
511        || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) {
512        *buffer = create_buffer(ds, pDraw, attachment, format);
513        return TRUE;
514
515    }
516    else {
517        *buffer = pPriv->buffers[old_buf];
518
519        if (ds->ReuseBufferNotify)
520            (*ds->ReuseBufferNotify) (pDraw, *buffer);
521
522        pPriv->buffers[old_buf] = NULL;
523        return FALSE;
524    }
525}
526
527static void
528update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
529                             DRI2BufferPtr * buffers, int out_count, int *width,
530                             int *height)
531{
532    int i;
533
534    if (pPriv->buffers != NULL) {
535        for (i = 0; i < pPriv->bufferCount; i++) {
536            if (pPriv->buffers[i] != NULL) {
537                destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
538            }
539        }
540
541        free(pPriv->buffers);
542    }
543
544    pPriv->buffers = buffers;
545    pPriv->bufferCount = out_count;
546    pPriv->width = pDraw->width;
547    pPriv->height = pDraw->height;
548    *width = pPriv->width;
549    *height = pPriv->height;
550}
551
552static DRI2BufferPtr *
553do_get_buffers(DrawablePtr pDraw, int *width, int *height,
554               unsigned int *attachments, int count, int *out_count,
555               int has_format)
556{
557    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
558    DRI2ScreenPtr ds;
559    DRI2BufferPtr *buffers;
560    int need_real_front = 0;
561    int need_fake_front = 0;
562    int have_fake_front = 0;
563    int front_format = 0;
564    int dimensions_match;
565    int buffers_changed = 0;
566    int i;
567
568    if (!pPriv) {
569        *width = pDraw->width;
570        *height = pDraw->height;
571        *out_count = 0;
572        return NULL;
573    }
574
575    ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
576
577    dimensions_match = (pDraw->width == pPriv->width)
578        && (pDraw->height == pPriv->height);
579
580    buffers = calloc((count + 1), sizeof(buffers[0]));
581    if (!buffers)
582        goto err_out;
583
584    for (i = 0; i < count; i++) {
585        const unsigned attachment = *(attachments++);
586        const unsigned format = (has_format) ? *(attachments++) : 0;
587
588        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
589                                     format, dimensions_match, &buffers[i]))
590            buffers_changed = 1;
591
592        if (buffers[i] == NULL)
593            goto err_out;
594
595        /* If the drawable is a window and the front-buffer is requested,
596         * silently add the fake front-buffer to the list of requested
597         * attachments.  The counting logic in the loop accounts for the case
598         * where the client requests both the fake and real front-buffer.
599         */
600        if (attachment == DRI2BufferBackLeft) {
601            need_real_front++;
602            front_format = format;
603        }
604
605        if (attachment == DRI2BufferFrontLeft) {
606            need_real_front--;
607            front_format = format;
608
609            if (pDraw->type == DRAWABLE_WINDOW) {
610                need_fake_front++;
611            }
612        }
613
614        if (pDraw->type == DRAWABLE_WINDOW) {
615            if (attachment == DRI2BufferFakeFrontLeft) {
616                need_fake_front--;
617                have_fake_front = 1;
618            }
619        }
620    }
621
622    if (need_real_front > 0) {
623        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
624                                     front_format, dimensions_match,
625                                     &buffers[i]))
626            buffers_changed = 1;
627
628        if (buffers[i] == NULL)
629            goto err_out;
630        i++;
631    }
632
633    if (need_fake_front > 0) {
634        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
635                                     front_format, dimensions_match,
636                                     &buffers[i]))
637            buffers_changed = 1;
638
639        if (buffers[i] == NULL)
640            goto err_out;
641
642        i++;
643        have_fake_front = 1;
644    }
645
646    *out_count = i;
647
648    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
649                                 height);
650
651    /* If the client is getting a fake front-buffer, pre-fill it with the
652     * contents of the real front-buffer.  This ensures correct operation of
653     * applications that call glXWaitX before calling glDrawBuffer.
654     */
655    if (have_fake_front && buffers_changed) {
656        BoxRec box;
657        RegionRec region;
658
659        box.x1 = 0;
660        box.y1 = 0;
661        box.x2 = pPriv->width;
662        box.y2 = pPriv->height;
663        RegionInit(&region, &box, 0);
664
665        DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
666                       DRI2BufferFrontLeft);
667    }
668
669    pPriv->needInvalidate = TRUE;
670
671    return pPriv->buffers;
672
673 err_out:
674
675    *out_count = 0;
676
677    if (buffers) {
678        for (i = 0; i < count; i++) {
679            if (buffers[i] != NULL)
680                destroy_buffer(pDraw, buffers[i], 0);
681        }
682
683        free(buffers);
684        buffers = NULL;
685    }
686
687    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
688                                 height);
689
690    return buffers;
691}
692
693DRI2BufferPtr *
694DRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
695               unsigned int *attachments, int count, int *out_count)
696{
697    return do_get_buffers(pDraw, width, height, attachments, count,
698                          out_count, FALSE);
699}
700
701DRI2BufferPtr *
702DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
703                         unsigned int *attachments, int count, int *out_count)
704{
705    return do_get_buffers(pDraw, width, height, attachments, count,
706                          out_count, TRUE);
707}
708
709static void
710DRI2InvalidateDrawable(DrawablePtr pDraw)
711{
712    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
713    DRI2DrawableRefPtr ref = NULL;
714
715    if (!pPriv || !pPriv->needInvalidate)
716        return;
717
718    pPriv->needInvalidate = FALSE;
719
720    xorg_list_for_each_entry(ref, &pPriv->reference_list, link)
721        ref->invalidate(pDraw, ref->priv, ref->id);
722}
723
724/*
725 * In the direct rendered case, we throttle the clients that have more
726 * than their share of outstanding swaps (and thus busy buffers) when a
727 * new GetBuffers request is received.  In the AIGLX case, we allow the
728 * client to get the new buffers, but throttle when the next GLX request
729 * comes in (see __glXDRIcontextWait()).
730 */
731Bool
732DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
733{
734    DRI2DrawablePtr pPriv;
735
736    pPriv = DRI2GetDrawable(pDraw);
737    if (pPriv == NULL)
738        return FALSE;
739
740    /* Throttle to swap limit */
741    if (pPriv->swapsPending >= pPriv->swap_limit) {
742        if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
743            ResetCurrentRequest(client);
744            client->sequence--;
745            return TRUE;
746        }
747    }
748
749    return FALSE;
750}
751
752void
753DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
754{
755    DRI2DrawablePtr pPriv;
756
757    pPriv = DRI2GetDrawable(pDraw);
758    if (pPriv == NULL)
759        return;
760
761    dri2Sleep(client, pPriv, WAKE_MSC);
762}
763
764static inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
765{
766    if (drawable->type == DRAWABLE_PIXMAP)
767        return (PixmapPtr)drawable;
768    else {
769        struct _Window *pWin = (struct _Window *)drawable;
770        return drawable->pScreen->GetWindowPixmap(pWin);
771    }
772}
773
774/*
775 * A TraverseTree callback to invalidate all windows using the same
776 * pixmap
777 */
778static int
779DRI2InvalidateWalk(WindowPtr pWin, void *data)
780{
781    if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data)
782        return WT_DONTWALKCHILDREN;
783    DRI2InvalidateDrawable(&pWin->drawable);
784    return WT_WALKCHILDREN;
785}
786
787static void
788DRI2InvalidateDrawableAll(DrawablePtr pDraw)
789{
790    if (pDraw->type == DRAWABLE_WINDOW) {
791        WindowPtr pWin = (WindowPtr) pDraw;
792        PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
793
794        /*
795         * Find the top-most window using this pixmap
796         */
797        while (pWin->parent &&
798               pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
799            pWin = pWin->parent;
800
801        /*
802         * Walk the sub-tree to invalidate all of the
803         * windows using the same pixmap
804         */
805        TraverseTree(pWin, DRI2InvalidateWalk, pPixmap);
806        DRI2InvalidateDrawable(&pPixmap->drawable);
807    }
808    else
809        DRI2InvalidateDrawable(pDraw);
810}
811
812DrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest)
813{
814    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
815    PixmapPtr spix;
816    PixmapPtr mpix = GetDrawablePixmap(pDraw);
817    ScreenPtr master, slave;
818    Bool ret;
819
820    master = mpix->drawable.pScreen;
821
822    if (pDraw->type == DRAWABLE_WINDOW) {
823        WindowPtr pWin = (WindowPtr)pDraw;
824        PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
825
826        if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) {
827            if (pPriv->redirectpixmap &&
828                pPriv->redirectpixmap->drawable.width == pDraw->width &&
829                pPriv->redirectpixmap->drawable.height == pDraw->height &&
830                pPriv->redirectpixmap->drawable.depth == pDraw->depth) {
831                mpix = pPriv->redirectpixmap;
832            } else {
833                if (master->ReplaceScanoutPixmap) {
834                    mpix = (*master->CreatePixmap)(master, pDraw->width, pDraw->height,
835                                                   pDraw->depth, CREATE_PIXMAP_USAGE_SHARED);
836                    if (!mpix)
837                        return NULL;
838
839                    ret = (*master->ReplaceScanoutPixmap)(pDraw, mpix, TRUE);
840                    if (ret == FALSE) {
841                        (*master->DestroyPixmap)(mpix);
842                        return NULL;
843                    }
844                    pPriv->redirectpixmap = mpix;
845                } else
846                    return NULL;
847            }
848        } else if (pPriv->redirectpixmap) {
849            (*master->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
850            (*master->DestroyPixmap)(pPriv->redirectpixmap);
851            pPriv->redirectpixmap = NULL;
852        }
853    }
854
855    slave = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
856
857    /* check if the pixmap is still fine */
858    if (pPriv->prime_slave_pixmap) {
859        if (pPriv->prime_slave_pixmap->master_pixmap == mpix)
860            return &pPriv->prime_slave_pixmap->drawable;
861        else {
862            (*pPriv->prime_slave_pixmap->master_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_slave_pixmap->master_pixmap);
863            (*slave->DestroyPixmap)(pPriv->prime_slave_pixmap);
864            pPriv->prime_slave_pixmap = NULL;
865        }
866    }
867
868    spix = PixmapShareToSlave(mpix, slave);
869    if (!spix)
870        return NULL;
871
872    pPriv->prime_slave_pixmap = spix;
873#ifdef COMPOSITE
874    spix->screen_x = mpix->screen_x;
875    spix->screen_y = mpix->screen_y;
876#endif
877
878    DRI2InvalidateDrawableAll(pDraw);
879    return &spix->drawable;
880}
881
882static void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
883                             DRI2BufferPtr pDest, DRI2BufferPtr pSrc)
884{
885    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
886    DRI2ScreenPtr ds;
887    ScreenPtr primeScreen;
888
889    primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
890    ds = DRI2GetScreen(primeScreen);
891
892    if (ds->CopyRegion2)
893        (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc);
894    else
895        (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc);
896
897    /* cause damage to the box */
898    if (pPriv->prime_id) {
899       BoxRec box;
900       RegionRec region;
901       box.x1 = 0;
902       box.x2 = box.x1 + pDraw->width;
903       box.y1 = 0;
904       box.y2 = box.y1 + pDraw->height;
905       RegionInit(&region, &box, 1);
906       RegionTranslate(&region, pDraw->x, pDraw->y);
907       DamageRegionAppend(pDraw, &region);
908       DamageRegionProcessPending(pDraw);
909       RegionUninit(&region);
910    }
911}
912
913int
914DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
915               unsigned int dest, unsigned int src)
916{
917    DRI2DrawablePtr pPriv;
918    DRI2BufferPtr pDestBuffer, pSrcBuffer;
919    int i;
920
921    pPriv = DRI2GetDrawable(pDraw);
922    if (pPriv == NULL)
923        return BadDrawable;
924
925    pDestBuffer = NULL;
926    pSrcBuffer = NULL;
927    for (i = 0; i < pPriv->bufferCount; i++) {
928        if (pPriv->buffers[i]->attachment == dest)
929            pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
930        if (pPriv->buffers[i]->attachment == src)
931            pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
932    }
933    if (pSrcBuffer == NULL || pDestBuffer == NULL)
934        return BadValue;
935
936    dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer);
937
938    return Success;
939}
940
941/* Can this drawable be page flipped? */
942Bool
943DRI2CanFlip(DrawablePtr pDraw)
944{
945    ScreenPtr pScreen = pDraw->pScreen;
946    WindowPtr pWin, pRoot;
947    PixmapPtr pWinPixmap, pRootPixmap;
948
949    if (pDraw->type == DRAWABLE_PIXMAP)
950        return TRUE;
951
952    pRoot = pScreen->root;
953    pRootPixmap = pScreen->GetWindowPixmap(pRoot);
954
955    pWin = (WindowPtr) pDraw;
956    pWinPixmap = pScreen->GetWindowPixmap(pWin);
957    if (pRootPixmap != pWinPixmap)
958        return FALSE;
959    if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
960        return FALSE;
961
962    /* Does the window match the pixmap exactly? */
963    if (pDraw->x != 0 || pDraw->y != 0 ||
964#ifdef COMPOSITE
965        pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y ||
966#endif
967        pDraw->width != pWinPixmap->drawable.width ||
968        pDraw->height != pWinPixmap->drawable.height)
969        return FALSE;
970
971    return TRUE;
972}
973
974/* Can we do a pixmap exchange instead of a blit? */
975Bool
976DRI2CanExchange(DrawablePtr pDraw)
977{
978    return FALSE;
979}
980
981void
982DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
983                    unsigned int tv_sec, unsigned int tv_usec)
984{
985    DRI2DrawablePtr pPriv;
986
987    pPriv = DRI2GetDrawable(pDraw);
988    if (pPriv == NULL)
989        return;
990
991    ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
992                         frame, pPriv->swap_count);
993
994    dri2WakeAll(client, pPriv, WAKE_MSC);
995}
996
997static void
998DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
999               unsigned int tv_sec, unsigned int tv_usec)
1000{
1001    ScreenPtr pScreen = pDraw->pScreen;
1002    DRI2DrawablePtr pPriv;
1003
1004    pPriv = DRI2GetDrawable(pDraw);
1005    if (pPriv == NULL) {
1006        xf86DrvMsg(pScreen->myNum, X_ERROR,
1007                   "[DRI2] %s: bad drawable\n", __func__);
1008        return;
1009    }
1010
1011    /*
1012     * Swap completed.
1013     * Wake the client iff:
1014     *   - it was waiting on SBC
1015     *   - was blocked due to GLX make current
1016     *   - was blocked due to swap throttling
1017     *   - is not blocked due to an MSC wait
1018     */
1019    if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) {
1020        if (dri2WakeAll(client, pPriv, WAKE_SBC)) {
1021            ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
1022                                 frame, pPriv->swap_count);
1023            pPriv->target_sbc = -1;
1024        }
1025    }
1026
1027    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
1028}
1029
1030void
1031DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
1032                 unsigned int tv_sec, unsigned int tv_usec, int type,
1033                 DRI2SwapEventPtr swap_complete, void *swap_data)
1034{
1035    ScreenPtr pScreen = pDraw->pScreen;
1036    DRI2DrawablePtr pPriv;
1037    CARD64 ust = 0;
1038    BoxRec box;
1039    RegionRec region;
1040
1041    pPriv = DRI2GetDrawable(pDraw);
1042    if (pPriv == NULL) {
1043        xf86DrvMsg(pScreen->myNum, X_ERROR,
1044                   "[DRI2] %s: bad drawable\n", __func__);
1045        return;
1046    }
1047
1048    pPriv->swapsPending--;
1049    pPriv->swap_count++;
1050
1051    box.x1 = 0;
1052    box.y1 = 0;
1053    box.x2 = pDraw->width;
1054    box.y2 = pDraw->height;
1055    RegionInit(&region, &box, 0);
1056    DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
1057                   DRI2BufferFrontLeft);
1058
1059    ust = ((CARD64) tv_sec * 1000000) + tv_usec;
1060    if (swap_complete)
1061        swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
1062
1063    pPriv->last_swap_msc = frame;
1064    pPriv->last_swap_ust = ust;
1065
1066    DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
1067}
1068
1069Bool
1070DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
1071{
1072    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
1073
1074    /* If we're currently waiting for a swap on this drawable, reset
1075     * the request and suspend the client. */
1076    if (pPriv && pPriv->swapsPending) {
1077        if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
1078            ResetCurrentRequest(client);
1079            client->sequence--;
1080            return TRUE;
1081        }
1082    }
1083
1084    return FALSE;
1085}
1086
1087
1088
1089int
1090DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
1091                CARD64 divisor, CARD64 remainder, CARD64 * swap_target,
1092                DRI2SwapEventPtr func, void *data)
1093{
1094    ScreenPtr pScreen = pDraw->pScreen;
1095    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
1096    DRI2DrawablePtr pPriv;
1097    DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
1098    int ret, i;
1099    CARD64 ust, current_msc;
1100
1101    pPriv = DRI2GetDrawable(pDraw);
1102    if (pPriv == NULL) {
1103        xf86DrvMsg(pScreen->myNum, X_ERROR,
1104                   "[DRI2] %s: bad drawable\n", __func__);
1105        return BadDrawable;
1106    }
1107
1108    /* According to spec, return expected swapbuffers count SBC after this swap
1109     * will complete. This is ignored unless we return Success, but it must be
1110     * initialized on every path where we return Success or the caller will send
1111     * an uninitialized value off the stack to the client. So let's initialize
1112     * it as early as possible, just to be sure.
1113     */
1114    *swap_target = pPriv->swap_count + pPriv->swapsPending + 1;
1115
1116    for (i = 0; i < pPriv->bufferCount; i++) {
1117        if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
1118            pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
1119        if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
1120            pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
1121    }
1122    if (pSrcBuffer == NULL || pDestBuffer == NULL) {
1123        xf86DrvMsg(pScreen->myNum, X_ERROR,
1124                   "[DRI2] %s: drawable has no back or front?\n", __func__);
1125        return BadDrawable;
1126    }
1127
1128    /* Old DDX or no swap interval, just blit */
1129    if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) {
1130        BoxRec box;
1131        RegionRec region;
1132
1133        box.x1 = 0;
1134        box.y1 = 0;
1135        box.x2 = pDraw->width;
1136        box.y2 = pDraw->height;
1137        RegionInit(&region, &box, 0);
1138
1139        pPriv->swapsPending++;
1140
1141        dri2_copy_region(pDraw, &region, pDestBuffer, pSrcBuffer);
1142        DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
1143                         func, data);
1144        return Success;
1145    }
1146
1147    /*
1148     * In the simple glXSwapBuffers case, all params will be 0, and we just
1149     * need to schedule a swap for the last swap target + the swap interval.
1150     */
1151    if (target_msc == 0 && divisor == 0 && remainder == 0) {
1152        /* If the current vblank count of the drawable's crtc is lower
1153         * than the count stored in last_swap_target from a previous swap
1154         * then reinitialize last_swap_target to the current crtc's msc,
1155         * otherwise the swap will hang. This will happen if the drawable
1156         * is moved to a crtc with a lower refresh rate, or a crtc that just
1157         * got enabled.
1158         */
1159        if (ds->GetMSC) {
1160            if (!(*ds->GetMSC) (pDraw, &ust, &current_msc))
1161                pPriv->last_swap_target = 0;
1162
1163            if (current_msc < pPriv->last_swap_target)
1164                pPriv->last_swap_target = current_msc;
1165
1166        }
1167
1168        /*
1169         * Swap target for this swap is last swap target + swap interval since
1170         * we have to account for the current swap count, interval, and the
1171         * number of pending swaps.
1172         */
1173        target_msc = pPriv->last_swap_target + pPriv->swap_interval;
1174
1175    }
1176
1177    pPriv->swapsPending++;
1178    ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer,
1179                               &target_msc, divisor, remainder, func, data);
1180    if (!ret) {
1181        pPriv->swapsPending--;  /* didn't schedule */
1182        xf86DrvMsg(pScreen->myNum, X_ERROR,
1183                   "[DRI2] %s: driver failed to schedule swap\n", __func__);
1184        return BadDrawable;
1185    }
1186
1187    pPriv->last_swap_target = target_msc;
1188
1189    DRI2InvalidateDrawableAll(pDraw);
1190
1191    return Success;
1192}
1193
1194void
1195DRI2SwapInterval(DrawablePtr pDrawable, int interval)
1196{
1197    ScreenPtr pScreen = pDrawable->pScreen;
1198    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
1199
1200    if (pPriv == NULL) {
1201        xf86DrvMsg(pScreen->myNum, X_ERROR,
1202                   "[DRI2] %s: bad drawable\n", __func__);
1203        return;
1204    }
1205
1206    /* fixme: check against arbitrary max? */
1207    pPriv->swap_interval = interval;
1208}
1209
1210int
1211DRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc)
1212{
1213    ScreenPtr pScreen = pDraw->pScreen;
1214    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
1215    DRI2DrawablePtr pPriv;
1216    Bool ret;
1217
1218    pPriv = DRI2GetDrawable(pDraw);
1219    if (pPriv == NULL) {
1220        xf86DrvMsg(pScreen->myNum, X_ERROR,
1221                   "[DRI2] %s: bad drawable\n", __func__);
1222        return BadDrawable;
1223    }
1224
1225    if (!ds->GetMSC) {
1226        *ust = 0;
1227        *msc = 0;
1228        *sbc = pPriv->swap_count;
1229        return Success;
1230    }
1231
1232    /*
1233     * Spec needs to be updated to include unmapped or redirected
1234     * drawables
1235     */
1236
1237    ret = (*ds->GetMSC) (pDraw, ust, msc);
1238    if (!ret)
1239        return BadDrawable;
1240
1241    *sbc = pPriv->swap_count;
1242
1243    return Success;
1244}
1245
1246int
1247DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
1248            CARD64 divisor, CARD64 remainder)
1249{
1250    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
1251    DRI2DrawablePtr pPriv;
1252    Bool ret;
1253
1254    pPriv = DRI2GetDrawable(pDraw);
1255    if (pPriv == NULL)
1256        return BadDrawable;
1257
1258    /* Old DDX just completes immediately */
1259    if (!ds->ScheduleWaitMSC) {
1260        DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
1261
1262        return Success;
1263    }
1264
1265    ret =
1266        (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder);
1267    if (!ret)
1268        return BadDrawable;
1269
1270    return Success;
1271}
1272
1273int
1274DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
1275{
1276    DRI2DrawablePtr pPriv;
1277
1278    pPriv = DRI2GetDrawable(pDraw);
1279    if (pPriv == NULL)
1280        return BadDrawable;
1281
1282    if (pPriv->target_sbc != -1) /* already in use */
1283        return BadDrawable;
1284
1285    /* target_sbc == 0 means to block until all pending swaps are
1286     * finished. Recalculate target_sbc to get that behaviour.
1287     */
1288    if (target_sbc == 0)
1289        target_sbc = pPriv->swap_count + pPriv->swapsPending;
1290
1291    /* If current swap count already >= target_sbc, reply and
1292     * return immediately with (ust, msc, sbc) triplet of
1293     * most recent completed swap.
1294     */
1295    if (pPriv->swap_count >= target_sbc) {
1296        ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
1297                             pPriv->last_swap_msc, pPriv->swap_count);
1298        return Success;
1299    }
1300
1301    if (!dri2Sleep(client, pPriv, WAKE_SBC))
1302        return BadAlloc;
1303
1304    pPriv->target_sbc = target_sbc;
1305    return Success;
1306}
1307
1308Bool
1309DRI2HasSwapControl(ScreenPtr pScreen)
1310{
1311    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1312
1313    return ds->ScheduleSwap && ds->GetMSC;
1314}
1315
1316Bool
1317DRI2Connect(ClientPtr client, ScreenPtr pScreen,
1318            unsigned int driverType, int *fd,
1319            const char **driverName, const char **deviceName)
1320{
1321    DRI2ScreenPtr ds;
1322    uint32_t prime_id = DRI2DriverPrimeId(driverType);
1323    uint32_t driver_id = driverType & 0xffff;
1324
1325    if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
1326        return FALSE;
1327
1328    ds = DRI2GetScreenPrime(pScreen, prime_id);
1329    if (ds == NULL)
1330        return FALSE;
1331
1332    if (driver_id >= ds->numDrivers ||
1333        !ds->driverNames[driver_id])
1334        return FALSE;
1335
1336    *driverName = ds->driverNames[driver_id];
1337    *deviceName = ds->deviceName;
1338    *fd = ds->fd;
1339
1340    if (client) {
1341        DRI2ClientPtr dri2_client;
1342        dri2_client = dri2ClientPrivate(client);
1343        dri2_client->prime_id = prime_id;
1344    }
1345
1346    return TRUE;
1347}
1348
1349static int
1350DRI2AuthMagic (ScreenPtr pScreen, uint32_t magic)
1351{
1352    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1353    if (ds == NULL)
1354        return -EINVAL;
1355
1356    return (*ds->LegacyAuthMagic) (ds->fd, magic);
1357}
1358
1359Bool
1360DRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic)
1361{
1362    DRI2ScreenPtr ds;
1363    DRI2ClientPtr dri2_client = dri2ClientPrivate(client);
1364    ScreenPtr primescreen;
1365
1366    ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id);
1367    if (ds == NULL)
1368        return FALSE;
1369
1370    primescreen = GetScreenPrime(pScreen, dri2_client->prime_id);
1371    if ((*ds->AuthMagic)(primescreen, magic))
1372        return FALSE;
1373    return TRUE;
1374}
1375
1376static int
1377DRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
1378                 WindowPtr pSib)
1379{
1380    DrawablePtr pDraw = (DrawablePtr) pWin;
1381    ScreenPtr pScreen = pDraw->pScreen;
1382    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1383    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
1384    int ret;
1385
1386    if (ds->ConfigNotify) {
1387        pScreen->ConfigNotify = ds->ConfigNotify;
1388
1389        ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib);
1390
1391        ds->ConfigNotify = pScreen->ConfigNotify;
1392        pScreen->ConfigNotify = DRI2ConfigNotify;
1393        if (ret)
1394            return ret;
1395    }
1396
1397    if (!dd || (dd->width == w && dd->height == h))
1398        return Success;
1399
1400    DRI2InvalidateDrawable(pDraw);
1401    return Success;
1402}
1403
1404static void
1405DRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix)
1406{
1407    ScreenPtr pScreen = pWin->drawable.pScreen;
1408    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1409
1410    pScreen->SetWindowPixmap = ds->SetWindowPixmap;
1411    (*pScreen->SetWindowPixmap) (pWin, pPix);
1412    ds->SetWindowPixmap = pScreen->SetWindowPixmap;
1413    pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
1414
1415    DRI2InvalidateDrawable(&pWin->drawable);
1416}
1417
1418#define MAX_PRIME DRI2DriverPrimeMask
1419static int
1420get_prime_id(void)
1421{
1422    int i;
1423    /* start at 1, prime id 0 is just normal driver */
1424    for (i = 1; i < MAX_PRIME; i++) {
1425         if (prime_id_allocate_bitmask & (1 << i))
1426             continue;
1427
1428         prime_id_allocate_bitmask |= (1 << i);
1429         return i;
1430    }
1431    return -1;
1432}
1433
1434#include "pci_ids/pci_id_driver_map.h"
1435
1436static char *
1437dri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info)
1438{
1439    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1440    EntityInfoPtr pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
1441    struct pci_device *pdev = NULL;
1442    int i, j;
1443
1444    if (pEnt)
1445        pdev = xf86GetPciInfoForEntity(pEnt->index);
1446
1447    /* For non-PCI devices, just assume that the 3D driver is named
1448     * the same as the kernel driver.  This is currently true for vc4
1449     * and msm (freedreno).
1450     */
1451    if (!pdev) {
1452        drmVersionPtr version = drmGetVersion(info->fd);
1453        char *kernel_driver;
1454
1455        if (!version) {
1456            xf86DrvMsg(pScreen->myNum, X_ERROR,
1457                       "[DRI2] Couldn't drmGetVersion() on non-PCI device, "
1458                       "no driver name found.\n");
1459            return NULL;
1460        }
1461
1462        kernel_driver = strndup(version->name, version->name_len);
1463        drmFreeVersion(version);
1464        return kernel_driver;
1465    }
1466
1467    for (i = 0; driver_map[i].driver; i++) {
1468        if (pdev->vendor_id != driver_map[i].vendor_id)
1469            continue;
1470
1471        if (driver_map[i].num_chips_ids == -1)
1472            return strdup(driver_map[i].driver);
1473
1474        for (j = 0; j < driver_map[i].num_chips_ids; j++) {
1475            if (driver_map[i].chip_ids[j] == pdev->device_id)
1476                return strdup(driver_map[i].driver);
1477        }
1478    }
1479
1480    xf86DrvMsg(pScreen->myNum, X_ERROR,
1481               "[DRI2] No driver mapping found for PCI device "
1482               "0x%04x / 0x%04x\n",
1483               pdev->vendor_id, pdev->device_id);
1484    return NULL;
1485}
1486
1487Bool
1488DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
1489{
1490    DRI2ScreenPtr ds;
1491
1492    const char *driverTypeNames[] = {
1493        "DRI",                  /* DRI2DriverDRI */
1494        "VDPAU",                /* DRI2DriverVDPAU */
1495    };
1496    unsigned int i;
1497    CARD8 cur_minor;
1498
1499    if (info->version < 3)
1500        return FALSE;
1501
1502    if (!xf86VGAarbiterAllowDRI(pScreen)) {
1503        xf86DrvMsg(pScreen->myNum, X_WARNING,
1504                   "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n");
1505        return FALSE;
1506    }
1507
1508    if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1509        return FALSE;
1510
1511    if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
1512        return FALSE;
1513
1514    if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
1515        return FALSE;
1516
1517    if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec)))
1518        return FALSE;
1519
1520    ds = calloc(1, sizeof *ds);
1521    if (!ds)
1522        return FALSE;
1523
1524    ds->screen = pScreen;
1525    ds->fd = info->fd;
1526    ds->deviceName = info->deviceName;
1527    dri2_major = 1;
1528
1529    ds->CreateBuffer = info->CreateBuffer;
1530    ds->DestroyBuffer = info->DestroyBuffer;
1531    ds->CopyRegion = info->CopyRegion;
1532
1533    if (info->version >= 4) {
1534        ds->ScheduleSwap = info->ScheduleSwap;
1535        ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
1536        ds->GetMSC = info->GetMSC;
1537        cur_minor = 3;
1538    }
1539    else {
1540        cur_minor = 1;
1541    }
1542
1543    if (info->version >= 8) {
1544        ds->AuthMagic = info->AuthMagic2;
1545    }
1546    if (info->version >= 5) {
1547        ds->LegacyAuthMagic = info->AuthMagic;
1548    }
1549
1550    if (info->version >= 6) {
1551        ds->ReuseBufferNotify = info->ReuseBufferNotify;
1552        ds->SwapLimitValidate = info->SwapLimitValidate;
1553    }
1554
1555    if (info->version >= 7) {
1556        ds->GetParam = info->GetParam;
1557        cur_minor = 4;
1558    }
1559
1560    if (info->version >= 9) {
1561        ds->CreateBuffer2 = info->CreateBuffer2;
1562        if (info->CreateBuffer2 && pScreen->isGPU) {
1563            ds->prime_id = get_prime_id();
1564            if (ds->prime_id == -1) {
1565                free(ds);
1566                return FALSE;
1567            }
1568        }
1569        ds->DestroyBuffer2 = info->DestroyBuffer2;
1570        ds->CopyRegion2 = info->CopyRegion2;
1571    }
1572
1573    /*
1574     * if the driver doesn't provide an AuthMagic function or the info struct
1575     * version is too low, call through LegacyAuthMagic
1576     */
1577    if (!ds->AuthMagic) {
1578        ds->AuthMagic = DRI2AuthMagic;
1579        /*
1580         * If the driver doesn't provide an AuthMagic function
1581         * it relies on the old method (using libdrm) or fails
1582         */
1583        if (!ds->LegacyAuthMagic)
1584#ifdef WITH_LIBDRM
1585            ds->LegacyAuthMagic = drmAuthMagic;
1586#else
1587            goto err_out;
1588#endif
1589    }
1590
1591    /* Initialize minor if needed and set to minimum provied by DDX */
1592    if (!dri2_minor || dri2_minor > cur_minor)
1593        dri2_minor = cur_minor;
1594
1595    if (info->version == 3 || info->numDrivers == 0) {
1596        /* Driver too old: use the old-style driverName field */
1597        ds->numDrivers = info->driverName ? 1 : 2;
1598        ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames));
1599        if (!ds->driverNames)
1600            goto err_out;
1601
1602        if (info->driverName) {
1603            ds->driverNames[0] = info->driverName;
1604        } else {
1605            ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info);
1606            if (!ds->driverNames[0])
1607                return FALSE;
1608        }
1609    }
1610    else {
1611        ds->numDrivers = info->numDrivers;
1612        ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames));
1613        if (!ds->driverNames)
1614            goto err_out;
1615        memcpy(ds->driverNames, info->driverNames,
1616               info->numDrivers * sizeof(*ds->driverNames));
1617    }
1618
1619    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
1620
1621    ds->ConfigNotify = pScreen->ConfigNotify;
1622    pScreen->ConfigNotify = DRI2ConfigNotify;
1623
1624    ds->SetWindowPixmap = pScreen->SetWindowPixmap;
1625    pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
1626
1627    xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
1628    for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) {
1629        if (i < ds->numDrivers && ds->driverNames[i]) {
1630            xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
1631                       driverTypeNames[i], ds->driverNames[i]);
1632        }
1633    }
1634
1635    return TRUE;
1636
1637 err_out:
1638    xf86DrvMsg(pScreen->myNum, X_WARNING,
1639               "[DRI2] Initialization failed for info version %d.\n",
1640               info->version);
1641    free(ds);
1642    return FALSE;
1643}
1644
1645void
1646DRI2CloseScreen(ScreenPtr pScreen)
1647{
1648    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1649
1650    pScreen->ConfigNotify = ds->ConfigNotify;
1651    pScreen->SetWindowPixmap = ds->SetWindowPixmap;
1652
1653    if (ds->prime_id)
1654        prime_id_allocate_bitmask &= ~(1 << ds->prime_id);
1655    free(ds->driverNames);
1656    free(ds);
1657    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
1658}
1659
1660/* Called by InitExtensions() */
1661Bool
1662DRI2ModuleSetup(void)
1663{
1664    dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
1665    if (!dri2DrawableRes)
1666        return FALSE;
1667
1668    return TRUE;
1669}
1670
1671void
1672DRI2Version(int *major, int *minor)
1673{
1674    if (major != NULL)
1675        *major = 1;
1676
1677    if (minor != NULL)
1678        *minor = 2;
1679}
1680
1681int
1682DRI2GetParam(ClientPtr client,
1683             DrawablePtr drawable,
1684             CARD64 param,
1685             BOOL *is_param_recognized,
1686             CARD64 *value)
1687{
1688    DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen);
1689    char high_byte = (param >> 24);
1690
1691    switch (high_byte) {
1692    case 0:
1693        /* Parameter names whose high_byte is 0 are reserved for the X
1694         * server. The server currently recognizes no parameters.
1695         */
1696        goto not_recognized;
1697    case 1:
1698        /* Parameter names whose high byte is 1 are reserved for the DDX. */
1699        if (ds->GetParam)
1700            return ds->GetParam(client, drawable, param,
1701                                is_param_recognized, value);
1702        else
1703            goto not_recognized;
1704    default:
1705        /* Other parameter names are reserved for future use. They are never
1706         * recognized.
1707         */
1708        goto not_recognized;
1709    }
1710
1711not_recognized:
1712    *is_param_recognized = FALSE;
1713    return Success;
1714}
1715