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