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