glx: Don't create a shared context if the other context isn't the same kind
[mesa.git] / src / glx / dri2_glx.c
1 /*
2 * Copyright © 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 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
34
35 #include <X11/Xlib.h>
36 #include <X11/extensions/Xfixes.h>
37 #include "glapi.h"
38 #include "glxclient.h"
39 #include <X11/extensions/dri2proto.h>
40 #include "xf86dri.h"
41 #include <dlfcn.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/mman.h>
46 #include "xf86drm.h"
47 #include "dri2.h"
48 #include "dri_common.h"
49
50 /* From xmlpool/options.h, user exposed so should be stable */
51 #define DRI_CONF_VBLANK_NEVER 0
52 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
53 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
54 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3
55
56 #undef DRI2_MINOR
57 #define DRI2_MINOR 1
58
59 struct dri2_display
60 {
61 __GLXDRIdisplay base;
62
63 /*
64 ** XFree86-DRI version information
65 */
66 int driMajor;
67 int driMinor;
68 int driPatch;
69 int swapAvailable;
70 int invalidateAvailable;
71
72 __glxHashTable *dri2Hash;
73
74 const __DRIextension *loader_extensions[4];
75 };
76
77 struct dri2_screen {
78 struct glx_screen base;
79
80 __DRIscreen *driScreen;
81 __GLXDRIscreen vtable;
82 const __DRIdri2Extension *dri2;
83 const __DRIcoreExtension *core;
84
85 const __DRI2flushExtension *f;
86 const __DRI2configQueryExtension *config;
87 const __DRItexBufferExtension *texBuffer;
88 const __DRI2throttleExtension *throttle;
89 const __DRIconfig **driver_configs;
90
91 void *driver;
92 int fd;
93 };
94
95 struct dri2_context
96 {
97 struct glx_context base;
98 __DRIcontext *driContext;
99 };
100
101 struct dri2_drawable
102 {
103 __GLXDRIdrawable base;
104 __DRIdrawable *driDrawable;
105 __DRIbuffer buffers[5];
106 int bufferCount;
107 int width, height;
108 int have_back;
109 int have_fake_front;
110 int swap_interval;
111 };
112
113 static const struct glx_context_vtable dri2_context_vtable;
114
115 static void
116 dri2_destroy_context(struct glx_context *context)
117 {
118 struct dri2_context *pcp = (struct dri2_context *) context;
119 struct dri2_screen *psc = (struct dri2_screen *) context->psc;
120
121 driReleaseDrawables(&pcp->base);
122
123 if (context->xid)
124 glx_send_destroy_context(psc->base.dpy, context->xid);
125
126 if (context->extensions)
127 XFree((char *) context->extensions);
128
129 (*psc->core->destroyContext) (pcp->driContext);
130
131 Xfree(pcp);
132 }
133
134 static Bool
135 dri2_bind_context(struct glx_context *context, struct glx_context *old,
136 GLXDrawable draw, GLXDrawable read)
137 {
138 struct dri2_context *pcp = (struct dri2_context *) context;
139 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
140 struct dri2_drawable *pdraw, *pread;
141 struct dri2_display *pdp;
142
143 pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
144 pread = (struct dri2_drawable *) driFetchDrawable(context, read);
145
146 driReleaseDrawables(&pcp->base);
147
148 if (pdraw == NULL || pread == NULL)
149 return GLXBadDrawable;
150
151 if (!(*psc->core->bindContext) (pcp->driContext,
152 pdraw->driDrawable, pread->driDrawable))
153 return GLXBadContext;
154
155 /* If the server doesn't send invalidate events, we may miss a
156 * resize before the rendering starts. Invalidate the buffers now
157 * so the driver will recheck before rendering starts. */
158 pdp = (struct dri2_display *) psc->base.display;
159 if (!pdp->invalidateAvailable) {
160 dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable);
161 if (pread != pdraw)
162 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable);
163 }
164
165 return Success;
166 }
167
168 static void
169 dri2_unbind_context(struct glx_context *context, struct glx_context *new)
170 {
171 struct dri2_context *pcp = (struct dri2_context *) context;
172 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
173
174 (*psc->core->unbindContext) (pcp->driContext);
175 }
176
177 static struct glx_context *
178 dri2_create_context(struct glx_screen *base,
179 struct glx_config *config_base,
180 struct glx_context *shareList, int renderType)
181 {
182 struct dri2_context *pcp, *pcp_shared;
183 struct dri2_screen *psc = (struct dri2_screen *) base;
184 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
185 __DRIcontext *shared = NULL;
186
187 if (shareList) {
188 /* If the shareList context is not a DRI2 context, we cannot possibly
189 * create a DRI2 context that shares it.
190 */
191 if (shareList->vtable->destroy != dri2_destroy_context) {
192 return NULL;
193 }
194
195 pcp_shared = (struct dri2_context *) shareList;
196 shared = pcp_shared->driContext;
197 }
198
199 pcp = Xmalloc(sizeof *pcp);
200 if (pcp == NULL)
201 return NULL;
202
203 memset(pcp, 0, sizeof *pcp);
204 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
205 Xfree(pcp);
206 return NULL;
207 }
208
209 pcp->driContext =
210 (*psc->dri2->createNewContext) (psc->driScreen,
211 config->driConfig, shared, pcp);
212
213 if (pcp->driContext == NULL) {
214 Xfree(pcp);
215 return NULL;
216 }
217
218 pcp->base.vtable = &dri2_context_vtable;
219
220 return &pcp->base;
221 }
222
223 static void
224 dri2DestroyDrawable(__GLXDRIdrawable *base)
225 {
226 struct dri2_screen *psc = (struct dri2_screen *) base->psc;
227 struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
228 struct glx_display *dpyPriv = psc->base.display;
229 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
230
231 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
232 (*psc->core->destroyDrawable) (pdraw->driDrawable);
233
234 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
235 * now, as the application explicitly asked to destroy the GLX
236 * drawable. Otherwise, for legacy drawables, we let the DRI2
237 * drawable linger on the server, since there's no good way of
238 * knowing when the application is done with it. The server will
239 * destroy the DRI2 drawable when it destroys the X drawable or the
240 * client exits anyway. */
241 if (pdraw->base.xDrawable != pdraw->base.drawable)
242 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
243
244 Xfree(pdraw);
245 }
246
247 static __GLXDRIdrawable *
248 dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
249 GLXDrawable drawable, struct glx_config *config_base)
250 {
251 struct dri2_drawable *pdraw;
252 struct dri2_screen *psc = (struct dri2_screen *) base;
253 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
254 struct glx_display *dpyPriv;
255 struct dri2_display *pdp;
256 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
257
258 pdraw = Xmalloc(sizeof(*pdraw));
259 if (!pdraw)
260 return NULL;
261
262 memset(pdraw, 0, sizeof *pdraw);
263 pdraw->base.destroyDrawable = dri2DestroyDrawable;
264 pdraw->base.xDrawable = xDrawable;
265 pdraw->base.drawable = drawable;
266 pdraw->base.psc = &psc->base;
267 pdraw->bufferCount = 0;
268 pdraw->swap_interval = 1; /* default may be overridden below */
269 pdraw->have_back = 0;
270
271 if (psc->config)
272 psc->config->configQueryi(psc->driScreen,
273 "vblank_mode", &vblank_mode);
274
275 switch (vblank_mode) {
276 case DRI_CONF_VBLANK_NEVER:
277 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
278 pdraw->swap_interval = 0;
279 break;
280 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
281 case DRI_CONF_VBLANK_ALWAYS_SYNC:
282 default:
283 pdraw->swap_interval = 1;
284 break;
285 }
286
287 DRI2CreateDrawable(psc->base.dpy, xDrawable);
288
289 dpyPriv = __glXInitialize(psc->base.dpy);
290 pdp = (struct dri2_display *)dpyPriv->dri2Display;;
291 /* Create a new drawable */
292 pdraw->driDrawable =
293 (*psc->dri2->createNewDrawable) (psc->driScreen,
294 config->driConfig, pdraw);
295
296 if (!pdraw->driDrawable) {
297 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
298 Xfree(pdraw);
299 return NULL;
300 }
301
302 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
303 (*psc->core->destroyDrawable) (pdraw->driDrawable);
304 DRI2DestroyDrawable(psc->base.dpy, xDrawable);
305 Xfree(pdraw);
306 return None;
307 }
308
309
310 #ifdef X_DRI2SwapInterval
311 /*
312 * Make sure server has the same swap interval we do for the new
313 * drawable.
314 */
315 if (pdp->swapAvailable)
316 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
317 #endif
318
319 return &pdraw->base;
320 }
321
322 #ifdef X_DRI2GetMSC
323
324 static int
325 dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
326 int64_t *ust, int64_t *msc, int64_t *sbc)
327 {
328 CARD64 dri2_ust, dri2_msc, dri2_sbc;
329 int ret;
330
331 ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
332 &dri2_ust, &dri2_msc, &dri2_sbc);
333 *ust = dri2_ust;
334 *msc = dri2_msc;
335 *sbc = dri2_sbc;
336
337 return ret;
338 }
339
340 #endif
341
342
343 #ifdef X_DRI2WaitMSC
344
345 static int
346 dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
347 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
348 {
349 CARD64 dri2_ust, dri2_msc, dri2_sbc;
350 int ret;
351
352 ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
353 remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
354 *ust = dri2_ust;
355 *msc = dri2_msc;
356 *sbc = dri2_sbc;
357
358 return ret;
359 }
360
361 static int
362 dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
363 int64_t *msc, int64_t *sbc)
364 {
365 CARD64 dri2_ust, dri2_msc, dri2_sbc;
366 int ret;
367
368 ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
369 target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
370 *ust = dri2_ust;
371 *msc = dri2_msc;
372 *sbc = dri2_sbc;
373
374 return ret;
375 }
376
377 #endif /* X_DRI2WaitMSC */
378
379 /**
380 * dri2Throttle - Request driver throttling
381 *
382 * This function uses the DRI2 throttle extension to give the
383 * driver the opportunity to throttle on flush front, copysubbuffer
384 * and swapbuffers.
385 */
386 static void
387 dri2Throttle(struct dri2_screen *psc,
388 struct dri2_drawable *draw,
389 enum __DRI2throttleReason reason)
390 {
391 if (psc->throttle) {
392 struct glx_context *gc = __glXGetCurrentContext();
393 struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
394 __DRIcontext *ctx =
395 (dri2Ctx) ? dri2Ctx->driContext : NULL;
396
397 psc->throttle->throttle(ctx, draw->driDrawable, reason);
398 }
399 }
400
401 static void
402 __dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
403 int width, int height,
404 enum __DRI2throttleReason reason)
405 {
406 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
407 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
408 XRectangle xrect;
409 XserverRegion region;
410
411 /* Check we have the right attachments */
412 if (!priv->have_back)
413 return;
414
415 xrect.x = x;
416 xrect.y = priv->height - y - height;
417 xrect.width = width;
418 xrect.height = height;
419
420 #ifdef __DRI2_FLUSH
421 if (psc->f)
422 (*psc->f->flush) (priv->driDrawable);
423 #endif
424
425 dri2Throttle(psc, priv, reason);
426
427 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
428 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
429 DRI2BufferFrontLeft, DRI2BufferBackLeft);
430
431 /* Refresh the fake front (if present) after we just damaged the real
432 * front.
433 */
434 if (priv->have_fake_front)
435 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
436 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
437
438 XFixesDestroyRegion(psc->base.dpy, region);
439 }
440
441 static void
442 dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
443 int width, int height)
444 {
445 __dri2CopySubBuffer(pdraw, x, y, width, height,
446 __DRI2_THROTTLE_COPYSUBBUFFER);
447 }
448
449
450 static void
451 dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
452 {
453 XRectangle xrect;
454 XserverRegion region;
455 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
456
457 xrect.x = 0;
458 xrect.y = 0;
459 xrect.width = priv->width;
460 xrect.height = priv->height;
461
462 #ifdef __DRI2_FLUSH
463 if (psc->f)
464 (*psc->f->flush) (priv->driDrawable);
465 #endif
466
467 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
468 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
469 XFixesDestroyRegion(psc->base.dpy, region);
470
471 }
472
473 static void
474 dri2_wait_x(struct glx_context *gc)
475 {
476 struct dri2_drawable *priv = (struct dri2_drawable *)
477 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
478
479 if (priv == NULL || !priv->have_fake_front)
480 return;
481
482 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
483 }
484
485 static void
486 dri2_wait_gl(struct glx_context *gc)
487 {
488 struct dri2_drawable *priv = (struct dri2_drawable *)
489 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
490
491 if (priv == NULL || !priv->have_fake_front)
492 return;
493
494 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
495 }
496
497 static void
498 dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
499 {
500 struct glx_display *priv;
501 struct dri2_display *pdp;
502 struct glx_context *gc;
503 struct dri2_drawable *pdraw = loaderPrivate;
504 struct dri2_screen *psc;
505
506 if (!pdraw)
507 return;
508
509 if (!pdraw->base.psc)
510 return;
511
512 psc = (struct dri2_screen *) pdraw->base.psc;
513
514 priv = __glXInitialize(psc->base.dpy);
515 pdp = (struct dri2_display *) priv->dri2Display;
516 gc = __glXGetCurrentContext();
517
518 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
519
520 /* Old servers don't send invalidate events */
521 if (!pdp->invalidateAvailable)
522 dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
523
524 dri2_wait_gl(gc);
525 }
526
527
528 static void
529 dri2DestroyScreen(struct glx_screen *base)
530 {
531 struct dri2_screen *psc = (struct dri2_screen *) base;
532
533 /* Free the direct rendering per screen data */
534 (*psc->core->destroyScreen) (psc->driScreen);
535 driDestroyConfigs(psc->driver_configs);
536 close(psc->fd);
537 Xfree(psc);
538 }
539
540 /**
541 * Process list of buffer received from the server
542 *
543 * Processes the list of buffers received in a reply from the server to either
544 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
545 */
546 static void
547 process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
548 unsigned count)
549 {
550 int i;
551
552 pdraw->bufferCount = count;
553 pdraw->have_fake_front = 0;
554 pdraw->have_back = 0;
555
556 /* This assumes the DRI2 buffer attachment tokens matches the
557 * __DRIbuffer tokens. */
558 for (i = 0; i < count; i++) {
559 pdraw->buffers[i].attachment = buffers[i].attachment;
560 pdraw->buffers[i].name = buffers[i].name;
561 pdraw->buffers[i].pitch = buffers[i].pitch;
562 pdraw->buffers[i].cpp = buffers[i].cpp;
563 pdraw->buffers[i].flags = buffers[i].flags;
564 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
565 pdraw->have_fake_front = 1;
566 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
567 pdraw->have_back = 1;
568 }
569
570 }
571
572 unsigned dri2GetSwapEventType(Display* dpy, XID drawable)
573 {
574 struct glx_display *glx_dpy = __glXInitialize(dpy);
575 __GLXDRIdrawable *pdraw;
576 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
577 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
578 return 0;
579 return glx_dpy->codes->first_event + GLX_BufferSwapComplete;
580 }
581
582 static int64_t
583 dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
584 int64_t remainder)
585 {
586 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
587 struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
588 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
589 struct dri2_display *pdp =
590 (struct dri2_display *)dpyPriv->dri2Display;
591 CARD64 ret = 0;
592
593 /* Check we have the right attachments */
594 if (!priv->have_back)
595 return ret;
596
597 /* Old servers can't handle swapbuffers */
598 if (!pdp->swapAvailable) {
599 __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
600 __DRI2_THROTTLE_SWAPBUFFER);
601 } else {
602 #ifdef X_DRI2SwapBuffers
603 #ifdef __DRI2_FLUSH
604 if (psc->f) {
605 struct glx_context *gc = __glXGetCurrentContext();
606
607 if (gc) {
608 (*psc->f->flush)(priv->driDrawable);
609 }
610 }
611 #endif
612
613 dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER);
614
615 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable,
616 target_msc, divisor, remainder, &ret);
617 #endif
618 }
619
620 /* Old servers don't send invalidate events */
621 if (!pdp->invalidateAvailable)
622 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
623
624 return ret;
625 }
626
627 static __DRIbuffer *
628 dri2GetBuffers(__DRIdrawable * driDrawable,
629 int *width, int *height,
630 unsigned int *attachments, int count,
631 int *out_count, void *loaderPrivate)
632 {
633 struct dri2_drawable *pdraw = loaderPrivate;
634 DRI2Buffer *buffers;
635
636 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
637 width, height, attachments, count, out_count);
638 if (buffers == NULL)
639 return NULL;
640
641 pdraw->width = *width;
642 pdraw->height = *height;
643 process_buffers(pdraw, buffers, *out_count);
644
645 Xfree(buffers);
646
647 return pdraw->buffers;
648 }
649
650 static __DRIbuffer *
651 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
652 int *width, int *height,
653 unsigned int *attachments, int count,
654 int *out_count, void *loaderPrivate)
655 {
656 struct dri2_drawable *pdraw = loaderPrivate;
657 DRI2Buffer *buffers;
658
659 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
660 pdraw->base.xDrawable,
661 width, height, attachments,
662 count, out_count);
663 if (buffers == NULL)
664 return NULL;
665
666 pdraw->width = *width;
667 pdraw->height = *height;
668 process_buffers(pdraw, buffers, *out_count);
669
670 Xfree(buffers);
671
672 return pdraw->buffers;
673 }
674
675 #ifdef X_DRI2SwapInterval
676
677 static int
678 dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
679 {
680 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
681 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
682 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
683
684 if (psc->config)
685 psc->config->configQueryi(psc->driScreen,
686 "vblank_mode", &vblank_mode);
687
688 switch (vblank_mode) {
689 case DRI_CONF_VBLANK_NEVER:
690 return GLX_BAD_VALUE;
691 case DRI_CONF_VBLANK_ALWAYS_SYNC:
692 if (interval <= 0)
693 return GLX_BAD_VALUE;
694 break;
695 default:
696 break;
697 }
698
699 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
700 priv->swap_interval = interval;
701
702 return 0;
703 }
704
705 static int
706 dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
707 {
708 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
709
710 return priv->swap_interval;
711 }
712
713 #endif /* X_DRI2SwapInterval */
714
715 static const __DRIdri2LoaderExtension dri2LoaderExtension = {
716 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
717 dri2GetBuffers,
718 dri2FlushFrontBuffer,
719 dri2GetBuffersWithFormat,
720 };
721
722 static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
723 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
724 dri2GetBuffers,
725 dri2FlushFrontBuffer,
726 NULL,
727 };
728
729 #ifdef __DRI_USE_INVALIDATE
730 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
731 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
732 };
733 #endif
734
735 _X_HIDDEN void
736 dri2InvalidateBuffers(Display *dpy, XID drawable)
737 {
738 __GLXDRIdrawable *pdraw =
739 dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
740 struct dri2_screen *psc;
741 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
742
743 if (!pdraw)
744 return;
745
746 psc = (struct dri2_screen *) pdraw->psc;
747
748 #if __DRI2_FLUSH_VERSION >= 3
749 if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
750 psc->f->invalidate(pdp->driDrawable);
751 #endif
752 }
753
754 static void
755 dri2_bind_tex_image(Display * dpy,
756 GLXDrawable drawable,
757 int buffer, const int *attrib_list)
758 {
759 struct glx_context *gc = __glXGetCurrentContext();
760 struct dri2_context *pcp = (struct dri2_context *) gc;
761 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
762 struct glx_display *dpyPriv = __glXInitialize(dpy);
763 struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
764 struct dri2_display *pdp =
765 (struct dri2_display *) dpyPriv->dri2Display;
766 struct dri2_screen *psc;
767
768 if (pdraw != NULL) {
769 psc = (struct dri2_screen *) base->psc;
770
771 #if __DRI2_FLUSH_VERSION >= 3
772 if (!pdp->invalidateAvailable && psc->f &&
773 psc->f->base.version >= 3 && psc->f->invalidate)
774 psc->f->invalidate(pdraw->driDrawable);
775 #endif
776
777 if (psc->texBuffer->base.version >= 2 &&
778 psc->texBuffer->setTexBuffer2 != NULL) {
779 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
780 pdraw->base.textureTarget,
781 pdraw->base.textureFormat,
782 pdraw->driDrawable);
783 }
784 else {
785 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
786 pdraw->base.textureTarget,
787 pdraw->driDrawable);
788 }
789 }
790 }
791
792 static void
793 dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
794 {
795 #if __DRI_TEX_BUFFER_VERSION >= 3
796 struct glx_context *gc = __glXGetCurrentContext();
797 struct dri2_context *pcp = (struct dri2_context *) gc;
798 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
799 struct glx_display *dpyPriv = __glXInitialize(dpy);
800 struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
801 struct dri2_display *pdp =
802 (struct dri2_display *) dpyPriv->dri2Display;
803 struct dri2_screen *psc;
804
805 if (pdraw != NULL) {
806 psc = (struct dri2_screen *) base->psc;
807
808 if (psc->texBuffer->base.version >= 3 &&
809 psc->texBuffer->releaseTexBuffer != NULL) {
810 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
811 pdraw->base.textureTarget,
812 pdraw->driDrawable);
813 }
814 }
815 #endif
816 }
817
818 static const struct glx_context_vtable dri2_context_vtable = {
819 dri2_destroy_context,
820 dri2_bind_context,
821 dri2_unbind_context,
822 dri2_wait_gl,
823 dri2_wait_x,
824 DRI_glXUseXFont,
825 dri2_bind_tex_image,
826 dri2_release_tex_image,
827 NULL, /* get_proc_address */
828 };
829
830 static void
831 dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
832 {
833 int i;
834
835 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
836 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
837 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
838 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
839
840 /* FIXME: if DRI2 version supports it... */
841 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
842
843 for (i = 0; extensions[i]; i++) {
844 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
845 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
846 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
847 }
848
849 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
850 psc->f = (__DRI2flushExtension *) extensions[i];
851 /* internal driver extension, no GL extension exposed */
852 }
853
854 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
855 psc->config = (__DRI2configQueryExtension *) extensions[i];
856
857 if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
858 psc->throttle = (__DRI2throttleExtension *) extensions[i];
859 }
860 }
861
862 static const struct glx_screen_vtable dri2_screen_vtable = {
863 dri2_create_context
864 };
865
866 static struct glx_screen *
867 dri2CreateScreen(int screen, struct glx_display * priv)
868 {
869 const __DRIconfig **driver_configs;
870 const __DRIextension **extensions;
871 const struct dri2_display *const pdp = (struct dri2_display *)
872 priv->dri2Display;
873 struct dri2_screen *psc;
874 __GLXDRIscreen *psp;
875 struct glx_config *configs = NULL, *visuals = NULL;
876 char *driverName, *deviceName;
877 drm_magic_t magic;
878 int i;
879
880 psc = Xmalloc(sizeof *psc);
881 if (psc == NULL)
882 return NULL;
883
884 memset(psc, 0, sizeof *psc);
885 psc->fd = -1;
886
887 if (!glx_screen_init(&psc->base, screen, priv)) {
888 Xfree(psc);
889 return NULL;
890 }
891
892 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
893 &driverName, &deviceName)) {
894 glx_screen_cleanup(&psc->base);
895 XFree(psc);
896 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
897 return NULL;
898 }
899
900 psc->driver = driOpenDriver(driverName);
901 if (psc->driver == NULL) {
902 ErrorMessageF("driver pointer missing\n");
903 goto handle_error;
904 }
905
906 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
907 if (extensions == NULL) {
908 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
909 goto handle_error;
910 }
911
912 for (i = 0; extensions[i]; i++) {
913 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
914 psc->core = (__DRIcoreExtension *) extensions[i];
915 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
916 psc->dri2 = (__DRIdri2Extension *) extensions[i];
917 }
918
919 if (psc->core == NULL || psc->dri2 == NULL) {
920 ErrorMessageF("core dri or dri2 extension not found\n");
921 goto handle_error;
922 }
923
924 psc->fd = open(deviceName, O_RDWR);
925 if (psc->fd < 0) {
926 ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
927 goto handle_error;
928 }
929
930 if (drmGetMagic(psc->fd, &magic)) {
931 ErrorMessageF("failed to get magic\n");
932 goto handle_error;
933 }
934
935 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
936 ErrorMessageF("failed to authenticate magic %d\n", magic);
937 goto handle_error;
938 }
939
940
941 /* If the server does not support the protocol for
942 * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
943 */
944 psc->driScreen =
945 psc->dri2->createNewScreen(screen, psc->fd,
946 (const __DRIextension **)
947 &pdp->loader_extensions[0],
948 &driver_configs, psc);
949
950 if (psc->driScreen == NULL) {
951 ErrorMessageF("failed to create dri screen\n");
952 goto handle_error;
953 }
954
955 extensions = psc->core->getExtensions(psc->driScreen);
956 dri2BindExtensions(psc, extensions);
957
958 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
959 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
960
961 if (!configs || !visuals)
962 goto handle_error;
963
964 glx_config_destroy_list(psc->base.configs);
965 psc->base.configs = configs;
966 glx_config_destroy_list(psc->base.visuals);
967 psc->base.visuals = visuals;
968
969 psc->driver_configs = driver_configs;
970
971 psc->base.vtable = &dri2_screen_vtable;
972 psp = &psc->vtable;
973 psc->base.driScreen = psp;
974 psp->destroyScreen = dri2DestroyScreen;
975 psp->createDrawable = dri2CreateDrawable;
976 psp->swapBuffers = dri2SwapBuffers;
977 psp->getDrawableMSC = NULL;
978 psp->waitForMSC = NULL;
979 psp->waitForSBC = NULL;
980 psp->setSwapInterval = NULL;
981 psp->getSwapInterval = NULL;
982
983 if (pdp->driMinor >= 2) {
984 #ifdef X_DRI2GetMSC
985 psp->getDrawableMSC = dri2DrawableGetMSC;
986 #endif
987 #ifdef X_DRI2WaitMSC
988 psp->waitForMSC = dri2WaitForMSC;
989 psp->waitForSBC = dri2WaitForSBC;
990 #endif
991 #ifdef X_DRI2SwapInterval
992 psp->setSwapInterval = dri2SetSwapInterval;
993 psp->getSwapInterval = dri2GetSwapInterval;
994 #endif
995 #if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
996 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
997 #endif
998 }
999
1000 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
1001 * available.*/
1002 psp->copySubBuffer = dri2CopySubBuffer;
1003 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1004
1005 Xfree(driverName);
1006 Xfree(deviceName);
1007
1008 return &psc->base;
1009
1010 handle_error:
1011 if (configs)
1012 glx_config_destroy_list(configs);
1013 if (visuals)
1014 glx_config_destroy_list(visuals);
1015 if (psc->driScreen)
1016 psc->core->destroyScreen(psc->driScreen);
1017 psc->driScreen = NULL;
1018 if (psc->fd >= 0)
1019 close(psc->fd);
1020 if (psc->driver)
1021 dlclose(psc->driver);
1022
1023 Xfree(driverName);
1024 Xfree(deviceName);
1025 glx_screen_cleanup(&psc->base);
1026 XFree(psc);
1027
1028 return NULL;
1029 }
1030
1031 /* Called from __glXFreeDisplayPrivate.
1032 */
1033 static void
1034 dri2DestroyDisplay(__GLXDRIdisplay * dpy)
1035 {
1036 struct dri2_display *pdp = (struct dri2_display *) dpy;
1037
1038 __glxHashDestroy(pdp->dri2Hash);
1039 Xfree(dpy);
1040 }
1041
1042 _X_HIDDEN __GLXDRIdrawable *
1043 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
1044 {
1045 struct glx_display *d = __glXInitialize(dpy);
1046 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
1047 __GLXDRIdrawable *pdraw;
1048
1049 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
1050 return pdraw;
1051
1052 return NULL;
1053 }
1054
1055 /*
1056 * Allocate, initialize and return a __DRIdisplayPrivate object.
1057 * This is called from __glXInitialize() when we are given a new
1058 * display pointer.
1059 */
1060 _X_HIDDEN __GLXDRIdisplay *
1061 dri2CreateDisplay(Display * dpy)
1062 {
1063 struct dri2_display *pdp;
1064 int eventBase, errorBase, i;
1065
1066 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1067 return NULL;
1068
1069 pdp = Xmalloc(sizeof *pdp);
1070 if (pdp == NULL)
1071 return NULL;
1072
1073 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1074 Xfree(pdp);
1075 return NULL;
1076 }
1077
1078 pdp->driPatch = 0;
1079 pdp->swapAvailable = (pdp->driMinor >= 2);
1080 pdp->invalidateAvailable = (pdp->driMinor >= 3);
1081
1082 pdp->base.destroyDisplay = dri2DestroyDisplay;
1083 pdp->base.createScreen = dri2CreateScreen;
1084
1085 i = 0;
1086 if (pdp->driMinor < 1)
1087 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
1088 else
1089 pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
1090
1091 pdp->loader_extensions[i++] = &systemTimeExtension.base;
1092
1093 #ifdef __DRI_USE_INVALIDATE
1094 pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1095 #endif
1096 pdp->loader_extensions[i++] = NULL;
1097
1098 pdp->dri2Hash = __glxHashCreate();
1099 if (pdp->dri2Hash == NULL) {
1100 Xfree(pdp);
1101 return NULL;
1102 }
1103
1104 return &pdp->base;
1105 }
1106
1107 #endif /* GLX_DIRECT_RENDERING */