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