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 
52 CARD8 dri2_major;               /* version of DRI2 supported by DDX */
53 CARD8 dri2_minor;
54 
55 uint32_t prime_id_allocate_bitmask;
56 
57 static DevPrivateKeyRec dri2ScreenPrivateKeyRec;
58 
59 #define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
60 
61 static DevPrivateKeyRec dri2WindowPrivateKeyRec;
62 
63 #define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
64 
65 static DevPrivateKeyRec dri2PixmapPrivateKeyRec;
66 
67 #define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
68 
69 static DevPrivateKeyRec dri2ClientPrivateKeyRec;
70 
71 #define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
72 
73 #define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \
74                                                       dri2ClientPrivateKey))
75 
76 typedef struct _DRI2Client {
77     int prime_id;
78 } DRI2ClientRec, *DRI2ClientPtr;
79 
80 static RESTYPE dri2DrawableRes;
81 
82 typedef struct _DRI2Screen *DRI2ScreenPtr;
83 
84 typedef 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 
107 typedef 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 
138 static void
139 destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id);
140 
141 enum DRI2WakeType {
142     WAKE_SBC,
143     WAKE_MSC,
144     WAKE_SWAP,
145 };
146 
147 #define Wake(c, t) (void *)((uintptr_t)(c) | (t))
148 
149 static Bool
dri2WakeClient(ClientPtr client,void * closure)150 dri2WakeClient(ClientPtr client, void *closure)
151 {
152     ClientWakeup(client);
153     return TRUE;
154 }
155 
156 static Bool
dri2WakeAll(ClientPtr client,DRI2DrawablePtr pPriv,enum DRI2WakeType t)157 dri2WakeAll(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 
169 static Bool
dri2Sleep(ClientPtr client,DRI2DrawablePtr pPriv,enum DRI2WakeType t)170 dri2Sleep(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 
179 static DRI2ScreenPtr
DRI2GetScreen(ScreenPtr pScreen)180 DRI2GetScreen(ScreenPtr pScreen)
181 {
182     return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
183 }
184 
185 static ScreenPtr
GetScreenPrime(ScreenPtr master,int prime_id)186 GetScreenPrime(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 
208 static DRI2ScreenPtr
DRI2GetScreenPrime(ScreenPtr master,int prime_id)209 DRI2GetScreenPrime(ScreenPtr master, int prime_id)
210 {
211     ScreenPtr slave = GetScreenPrime(master, prime_id);
212     return DRI2GetScreen(slave);
213 }
214 
215 static DRI2DrawablePtr
DRI2GetDrawable(DrawablePtr pDraw)216 DRI2GetDrawable(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 
233 static DRI2DrawablePtr
DRI2AllocateDrawable(DrawablePtr pDraw)234 DRI2AllocateDrawable(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 
280 Bool
DRI2SwapLimit(DrawablePtr pDraw,int swap_limit)281 DRI2SwapLimit(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 
304 typedef struct DRI2DrawableRefRec {
305     XID id;
306     XID dri2_id;
307     DRI2InvalidateProcPtr invalidate;
308     void *priv;
309     struct xorg_list link;
310 } DRI2DrawableRefRec, *DRI2DrawableRefPtr;
311 
312 static DRI2DrawableRefPtr
DRI2LookupDrawableRef(DRI2DrawablePtr pPriv,XID id)313 DRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
314 {
315     DRI2DrawableRefPtr ref;
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 
325 static int
DRI2AddDrawableRef(DRI2DrawablePtr pPriv,XID id,XID dri2_id,DRI2InvalidateProcPtr invalidate,void * priv)326 DRI2AddDrawableRef(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 
355 int
DRI2CreateDrawable2(ClientPtr client,DrawablePtr pDraw,XID id,DRI2InvalidateProcPtr invalidate,void * priv,XID * dri2_id_out)356 DRI2CreateDrawable2(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 
384 int
DRI2CreateDrawable(ClientPtr client,DrawablePtr pDraw,XID id,DRI2InvalidateProcPtr invalidate,void * priv)385 DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
386                    DRI2InvalidateProcPtr invalidate, void *priv)
387 {
388     return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL);
389 }
390 
391 static int
DRI2DrawableGone(void * p,XID id)392 DRI2DrawableGone(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 
458 static DRI2BufferPtr
create_buffer(DRI2ScreenPtr ds,DrawablePtr pDraw,unsigned int attachment,unsigned int format)459 create_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 
472 static void
destroy_buffer(DrawablePtr pDraw,DRI2BufferPtr buffer,int prime_id)473 destroy_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 
485 static int
find_attachment(DRI2DrawablePtr pPriv,unsigned attachment)486 find_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 
504 static Bool
allocate_or_reuse_buffer(DrawablePtr pDraw,DRI2ScreenPtr ds,DRI2DrawablePtr pPriv,unsigned int attachment,unsigned int format,int dimensions_match,DRI2BufferPtr * buffer)505 allocate_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 
530 static void
update_dri2_drawable_buffers(DRI2DrawablePtr pPriv,DrawablePtr pDraw,DRI2BufferPtr * buffers,int out_count,int * width,int * height)531 update_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 
555 static DRI2BufferPtr *
do_get_buffers(DrawablePtr pDraw,int * width,int * height,unsigned int * attachments,int count,int * out_count,int has_format)556 do_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 
696 DRI2BufferPtr *
DRI2GetBuffers(DrawablePtr pDraw,int * width,int * height,unsigned int * attachments,int count,int * out_count)697 DRI2GetBuffers(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 
704 DRI2BufferPtr *
DRI2GetBuffersWithFormat(DrawablePtr pDraw,int * width,int * height,unsigned int * attachments,int count,int * out_count)705 DRI2GetBuffersWithFormat(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 
712 static void
DRI2InvalidateDrawable(DrawablePtr pDraw)713 DRI2InvalidateDrawable(DrawablePtr pDraw)
714 {
715     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
716     DRI2DrawableRefPtr ref;
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  */
734 Bool
DRI2ThrottleClient(ClientPtr client,DrawablePtr pDraw)735 DRI2ThrottleClient(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 
755 void
DRI2BlockClient(ClientPtr client,DrawablePtr pDraw)756 DRI2BlockClient(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 
GetDrawablePixmap(DrawablePtr drawable)767 static 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  */
781 static int
DRI2InvalidateWalk(WindowPtr pWin,void * data)782 DRI2InvalidateWalk(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 
790 static void
DRI2InvalidateDrawableAll(DrawablePtr pDraw)791 DRI2InvalidateDrawableAll(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 
DRI2UpdatePrime(DrawablePtr pDraw,DRI2BufferPtr pDest)815 DrawablePtr 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 
dri2_copy_region(DrawablePtr pDraw,RegionPtr pRegion,DRI2BufferPtr pDest,DRI2BufferPtr pSrc)886 static 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 
917 int
DRI2CopyRegion(DrawablePtr pDraw,RegionPtr pRegion,unsigned int dest,unsigned int src)918 DRI2CopyRegion(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? */
946 Bool
DRI2CanFlip(DrawablePtr pDraw)947 DRI2CanFlip(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? */
979 Bool
DRI2CanExchange(DrawablePtr pDraw)980 DRI2CanExchange(DrawablePtr pDraw)
981 {
982     return FALSE;
983 }
984 
985 void
DRI2WaitMSCComplete(ClientPtr client,DrawablePtr pDraw,int frame,unsigned int tv_sec,unsigned int tv_usec)986 DRI2WaitMSCComplete(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 
1001 static void
DRI2WakeClient(ClientPtr client,DrawablePtr pDraw,int frame,unsigned int tv_sec,unsigned int tv_usec)1002 DRI2WakeClient(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 
1034 void
DRI2SwapComplete(ClientPtr client,DrawablePtr pDraw,int frame,unsigned int tv_sec,unsigned int tv_usec,int type,DRI2SwapEventPtr swap_complete,void * swap_data)1035 DRI2SwapComplete(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 
1073 Bool
DRI2WaitSwap(ClientPtr client,DrawablePtr pDrawable)1074 DRI2WaitSwap(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 
1093 int
DRI2SwapBuffers(ClientPtr client,DrawablePtr pDraw,CARD64 target_msc,CARD64 divisor,CARD64 remainder,CARD64 * swap_target,DRI2SwapEventPtr func,void * data)1094 DRI2SwapBuffers(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 
1198 void
DRI2SwapInterval(DrawablePtr pDrawable,int interval)1199 DRI2SwapInterval(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 
1214 int
DRI2GetMSC(DrawablePtr pDraw,CARD64 * ust,CARD64 * msc,CARD64 * sbc)1215 DRI2GetMSC(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 
1250 int
DRI2WaitMSC(ClientPtr client,DrawablePtr pDraw,CARD64 target_msc,CARD64 divisor,CARD64 remainder)1251 DRI2WaitMSC(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 
1277 int
DRI2WaitSBC(ClientPtr client,DrawablePtr pDraw,CARD64 target_sbc)1278 DRI2WaitSBC(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 
1312 Bool
DRI2HasSwapControl(ScreenPtr pScreen)1313 DRI2HasSwapControl(ScreenPtr pScreen)
1314 {
1315     DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1316 
1317     return ds->ScheduleSwap && ds->GetMSC;
1318 }
1319 
1320 Bool
DRI2Connect(ClientPtr client,ScreenPtr pScreen,unsigned int driverType,int * fd,const char ** driverName,const char ** deviceName)1321 DRI2Connect(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 
1353 static int
DRI2AuthMagic(ScreenPtr pScreen,uint32_t magic)1354 DRI2AuthMagic (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 
1363 Bool
DRI2Authenticate(ClientPtr client,ScreenPtr pScreen,uint32_t magic)1364 DRI2Authenticate(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 
1380 static int
DRI2ConfigNotify(WindowPtr pWin,int x,int y,int w,int h,int bw,WindowPtr pSib)1381 DRI2ConfigNotify(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 
1408 static void
DRI2SetWindowPixmap(WindowPtr pWin,PixmapPtr pPix)1409 DRI2SetWindowPixmap(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
1423 static int
get_prime_id(void)1424 get_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 
1440 static char *
dri2_probe_driver_name(ScreenPtr pScreen,DRI2InfoPtr info)1441 dri2_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);
1488 out:
1489     drmFreeDevice(&dev);
1490     return driver;
1491 #else
1492     return NULL;
1493 #endif
1494 }
1495 
1496 Bool
DRI2ScreenInit(ScreenPtr pScreen,DRI2InfoPtr info)1497 DRI2ScreenInit(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 
1653 void
DRI2CloseScreen(ScreenPtr pScreen)1654 DRI2CloseScreen(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() */
1669 Bool
DRI2ModuleSetup(void)1670 DRI2ModuleSetup(void)
1671 {
1672     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
1673     if (!dri2DrawableRes)
1674         return FALSE;
1675 
1676     return TRUE;
1677 }
1678 
1679 void
DRI2Version(int * major,int * minor)1680 DRI2Version(int *major, int *minor)
1681 {
1682     if (major != NULL)
1683         *major = 1;
1684 
1685     if (minor != NULL)
1686         *minor = 2;
1687 }
1688 
1689 int
DRI2GetParam(ClientPtr client,DrawablePtr drawable,CARD64 param,BOOL * is_param_recognized,CARD64 * value)1690 DRI2GetParam(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 
1719 not_recognized:
1720     *is_param_recognized = FALSE;
1721     return Success;
1722 }
1723