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