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