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(®ion, &box, 0);
668
669 DRI2CopyRegion(pDraw, ®ion, 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(®ion, &box, 1);
911 RegionTranslate(®ion, pDraw->x, pDraw->y);
912 DamageRegionAppend(pDraw, ®ion);
913 DamageRegionProcessPending(pDraw);
914 RegionUninit(®ion);
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(®ion, &box, 0);
1061 DRI2CopyRegion(pDraw, ®ion, 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(®ion, &box, 0);
1143
1144 pPriv->swapsPending++;
1145
1146 dri2_copy_region(pDraw, ®ion, 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, ¤t_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