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