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