dri3: Fix two little memory leaks.
[mesa.git] / src / glx / dri3_glx.c
1 /*
2 * Copyright © 2013 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 /*
24 * Portions of this code were adapted from dri2_glx.c which carries the
25 * following copyright:
26 *
27 * Copyright © 2008 Red Hat, Inc.
28 *
29 * Permission is hereby granted, free of charge, to any person obtaining a
30 * copy of this software and associated documentation files (the "Soft-
31 * ware"), to deal in the Software without restriction, including without
32 * limitation the rights to use, copy, modify, merge, publish, distribute,
33 * and/or sell copies of the Software, and to permit persons to whom the
34 * Software is furnished to do so, provided that the above copyright
35 * notice(s) and this permission notice appear in all copies of the Soft-
36 * ware and that both the above copyright notice(s) and this permission
37 * notice appear in supporting documentation.
38 *
39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
41 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
42 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
43 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
44 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
45 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
46 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
47 * MANCE OF THIS SOFTWARE.
48 *
49 * Except as contained in this notice, the name of a copyright holder shall
50 * not be used in advertising or otherwise to promote the sale, use or
51 * other dealings in this Software without prior written authorization of
52 * the copyright holder.
53 *
54 * Authors:
55 * Kristian Høgsberg (krh@redhat.com)
56 */
57
58 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
59
60 #include <X11/Xlib.h>
61 #include <X11/extensions/Xfixes.h>
62 #include <X11/Xlib-xcb.h>
63 #include <X11/xshmfence.h>
64 #include <xcb/xcb.h>
65 #include <xcb/dri3.h>
66 #include <xcb/present.h>
67 #include <GL/gl.h>
68 #include "glapi.h"
69 #include "glxclient.h"
70 #include "xf86dri.h"
71 #include <dlfcn.h>
72 #include <fcntl.h>
73 #include <unistd.h>
74 #include <sys/types.h>
75 #include <sys/mman.h>
76 #include <sys/time.h>
77
78 #include "xf86drm.h"
79 #include "dri_common.h"
80 #include "dri3_priv.h"
81 #include "loader.h"
82
83 static const struct glx_context_vtable dri3_context_vtable;
84
85 static inline void
86 dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer)
87 {
88 xshmfence_reset(buffer->shm_fence);
89 }
90
91 static inline void
92 dri3_fence_set(struct dri3_buffer *buffer)
93 {
94 xshmfence_trigger(buffer->shm_fence);
95 }
96
97 static inline void
98 dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer)
99 {
100 xcb_sync_trigger_fence(c, buffer->sync_fence);
101 }
102
103 static inline void
104 dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer)
105 {
106 xcb_flush(c);
107 xshmfence_await(buffer->shm_fence);
108 }
109
110 static inline Bool
111 dri3_fence_triggered(struct dri3_buffer *buffer)
112 {
113 return xshmfence_query(buffer->shm_fence);
114 }
115
116 static void
117 dri3_destroy_context(struct glx_context *context)
118 {
119 struct dri3_context *pcp = (struct dri3_context *) context;
120 struct dri3_screen *psc = (struct dri3_screen *) context->psc;
121
122 driReleaseDrawables(&pcp->base);
123
124 free((char *) context->extensions);
125
126 (*psc->core->destroyContext) (pcp->driContext);
127
128 free(pcp);
129 }
130
131 static Bool
132 dri3_bind_context(struct glx_context *context, struct glx_context *old,
133 GLXDrawable draw, GLXDrawable read)
134 {
135 struct dri3_context *pcp = (struct dri3_context *) context;
136 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
137 struct dri3_drawable *pdraw, *pread;
138
139 pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw);
140 pread = (struct dri3_drawable *) driFetchDrawable(context, read);
141
142 driReleaseDrawables(&pcp->base);
143
144 if (pdraw == NULL || pread == NULL)
145 return GLXBadDrawable;
146
147 if (!(*psc->core->bindContext) (pcp->driContext,
148 pdraw->driDrawable, pread->driDrawable))
149 return GLXBadContext;
150
151 return Success;
152 }
153
154 static void
155 dri3_unbind_context(struct glx_context *context, struct glx_context *new)
156 {
157 struct dri3_context *pcp = (struct dri3_context *) context;
158 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
159
160 (*psc->core->unbindContext) (pcp->driContext);
161 }
162
163 static struct glx_context *
164 dri3_create_context_attribs(struct glx_screen *base,
165 struct glx_config *config_base,
166 struct glx_context *shareList,
167 unsigned num_attribs,
168 const uint32_t *attribs,
169 unsigned *error)
170 {
171 struct dri3_context *pcp = NULL;
172 struct dri3_context *pcp_shared = NULL;
173 struct dri3_screen *psc = (struct dri3_screen *) base;
174 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
175 __DRIcontext *shared = NULL;
176
177 uint32_t minor_ver = 1;
178 uint32_t major_ver = 2;
179 uint32_t flags = 0;
180 unsigned api;
181 int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
182 uint32_t ctx_attribs[2 * 5];
183 unsigned num_ctx_attribs = 0;
184 uint32_t render_type;
185
186 /* Remap the GLX tokens to DRI2 tokens.
187 */
188 if (!dri2_convert_glx_attribs(num_attribs, attribs,
189 &major_ver, &minor_ver,
190 &render_type, &flags, &api,
191 &reset, error))
192 goto error_exit;
193
194 /* Check the renderType value */
195 if (!validate_renderType_against_config(config_base, render_type))
196 goto error_exit;
197
198 if (shareList) {
199 pcp_shared = (struct dri3_context *) shareList;
200 shared = pcp_shared->driContext;
201 }
202
203 pcp = calloc(1, sizeof *pcp);
204 if (pcp == NULL) {
205 *error = __DRI_CTX_ERROR_NO_MEMORY;
206 goto error_exit;
207 }
208
209 if (!glx_context_init(&pcp->base, &psc->base, &config->base))
210 goto error_exit;
211
212 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
213 ctx_attribs[num_ctx_attribs++] = major_ver;
214 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
215 ctx_attribs[num_ctx_attribs++] = minor_ver;
216
217 /* Only send a value when the non-default value is requested. By doing
218 * this we don't have to check the driver's DRI3 version before sending the
219 * default value.
220 */
221 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
222 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
223 ctx_attribs[num_ctx_attribs++] = reset;
224 }
225
226 if (flags != 0) {
227 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
228
229 /* The current __DRI_CTX_FLAG_* values are identical to the
230 * GLX_CONTEXT_*_BIT values.
231 */
232 ctx_attribs[num_ctx_attribs++] = flags;
233 }
234
235 pcp->driContext =
236 (*psc->image_driver->createContextAttribs) (psc->driScreen,
237 api,
238 config->driConfig,
239 shared,
240 num_ctx_attribs / 2,
241 ctx_attribs,
242 error,
243 pcp);
244
245 if (pcp->driContext == NULL)
246 goto error_exit;
247
248 pcp->base.vtable = &dri3_context_vtable;
249
250 return &pcp->base;
251
252 error_exit:
253 free(pcp);
254
255 return NULL;
256 }
257
258 static struct glx_context *
259 dri3_create_context(struct glx_screen *base,
260 struct glx_config *config_base,
261 struct glx_context *shareList, int renderType)
262 {
263 unsigned int error;
264
265 return dri3_create_context_attribs(base, config_base, shareList,
266 0, NULL, &error);
267 }
268
269 static void
270 dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer);
271
272 static void
273 dri3_destroy_drawable(__GLXDRIdrawable *base)
274 {
275 struct dri3_screen *psc = (struct dri3_screen *) base->psc;
276 struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
277 xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy);
278 int i;
279
280 (*psc->core->destroyDrawable) (pdraw->driDrawable);
281
282 for (i = 0; i < DRI3_NUM_BUFFERS; i++) {
283 if (pdraw->buffers[i])
284 dri3_free_render_buffer(pdraw, pdraw->buffers[i]);
285 }
286
287 if (pdraw->special_event)
288 xcb_unregister_for_special_event(c, pdraw->special_event);
289 free(pdraw);
290 }
291
292 static __GLXDRIdrawable *
293 dri3_create_drawable(struct glx_screen *base, XID xDrawable,
294 GLXDrawable drawable, struct glx_config *config_base)
295 {
296 struct dri3_drawable *pdraw;
297 struct dri3_screen *psc = (struct dri3_screen *) base;
298 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
299 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
300
301 pdraw = calloc(1, sizeof(*pdraw));
302 if (!pdraw)
303 return NULL;
304
305 pdraw->base.destroyDrawable = dri3_destroy_drawable;
306 pdraw->base.xDrawable = xDrawable;
307 pdraw->base.drawable = drawable;
308 pdraw->base.psc = &psc->base;
309 pdraw->swap_interval = 1; /* default may be overridden below */
310 pdraw->have_back = 0;
311 pdraw->have_fake_front = 0;
312
313 if (psc->config)
314 psc->config->configQueryi(psc->driScreen,
315 "vblank_mode", &vblank_mode);
316
317 switch (vblank_mode) {
318 case DRI_CONF_VBLANK_NEVER:
319 case DRI_CONF_VBLANK_DEF_INTERVAL_0:
320 pdraw->swap_interval = 0;
321 break;
322 case DRI_CONF_VBLANK_DEF_INTERVAL_1:
323 case DRI_CONF_VBLANK_ALWAYS_SYNC:
324 default:
325 pdraw->swap_interval = 1;
326 break;
327 }
328
329 (void) __glXInitialize(psc->base.dpy);
330
331 /* Create a new drawable */
332 pdraw->driDrawable =
333 (*psc->image_driver->createNewDrawable) (psc->driScreen,
334 config->driConfig, pdraw);
335
336 if (!pdraw->driDrawable) {
337 free(pdraw);
338 return NULL;
339 }
340
341 /*
342 * Make sure server has the same swap interval we do for the new
343 * drawable.
344 */
345 if (psc->vtable.setSwapInterval)
346 psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
347
348 return &pdraw->base;
349 }
350
351 /*
352 * Process one Present event
353 */
354 static void
355 dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_t *ge)
356 {
357 switch (ge->evtype) {
358 case XCB_PRESENT_CONFIGURE_NOTIFY: {
359 xcb_present_configure_notify_event_t *ce = (void *) ge;
360
361 priv->width = ce->width;
362 priv->height = ce->height;
363 break;
364 }
365 case XCB_PRESENT_COMPLETE_NOTIFY: {
366 xcb_present_complete_notify_event_t *ce = (void *) ge;
367
368 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
369 priv->present_event_serial = ce->serial;
370 else
371 priv->present_msc_event_serial = ce->serial;
372 priv->ust = ce->ust;
373 priv->msc = ce->msc;
374 break;
375 }
376 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
377 xcb_present_idle_notify_event_t *ie = (void *) ge;
378 int b;
379
380 for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) {
381 struct dri3_buffer *buf = priv->buffers[b];
382
383 if (buf && buf->pixmap == ie->pixmap) {
384 buf->busy = 0;
385 break;
386 }
387 }
388 break;
389 }
390 }
391 free(ge);
392 }
393
394 static int
395 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
396 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
397 {
398 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
399 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
400 xcb_generic_event_t *ev;
401 xcb_present_generic_event_t *ge;
402
403 /* Ask for the an event for the target MSC */
404 ++priv->present_msc_request_serial;
405 xcb_present_notify_msc(c,
406 priv->base.xDrawable,
407 priv->present_msc_request_serial,
408 target_msc,
409 divisor,
410 remainder);
411
412 xcb_flush(c);
413
414 /* Wait for the event */
415 if (priv->special_event) {
416 while (priv->present_msc_request_serial != priv->present_msc_event_serial) {
417 ev = xcb_wait_for_special_event(c, priv->special_event);
418 if (!ev)
419 break;
420 ge = (void *) ev;
421 dri3_handle_present_event(priv, ge);
422 }
423 }
424
425 *ust = priv->ust;
426 *msc = priv->msc;
427 *sbc = priv->sbc;
428
429 return 1;
430 }
431
432 static int
433 dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
434 int64_t *ust, int64_t *msc, int64_t *sbc)
435 {
436 return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
437 }
438
439 /** dri3_wait_for_sbc
440 *
441 * Wait for the swap buffer count to increase. The only way this
442 * can happen is if some other thread is doing swap buffers as
443 * we no longer share swap buffer counts with other processes.
444 *
445 * I'm not sure this is actually useful as such, and so this
446 * implementation is a kludge that just polls once a second
447 */
448 static int
449 dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
450 int64_t *msc, int64_t *sbc)
451 {
452 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
453
454 while (priv->sbc < target_sbc) {
455 sleep(1);
456 }
457 return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc, sbc);
458 }
459
460 /**
461 * Asks the driver to flush any queued work necessary for serializing with the
462 * X command stream, and optionally the slightly more strict requirement of
463 * glFlush() equivalence (which would require flushing even if nothing had
464 * been drawn to a window system framebuffer, for example).
465 */
466 static void
467 dri3_flush(struct dri3_screen *psc,
468 struct dri3_drawable *draw,
469 unsigned flags,
470 enum __DRI2throttleReason throttle_reason)
471 {
472 struct glx_context *gc = __glXGetCurrentContext();
473
474 if (gc) {
475 struct dri3_context *dri3Ctx = (struct dri3_context *)gc;
476
477 (*psc->f->flush_with_flags)(dri3Ctx->driContext, draw->driDrawable, flags, throttle_reason);
478 }
479 }
480
481 static xcb_gcontext_t
482 dri3_drawable_gc(struct dri3_drawable *priv)
483 {
484 if (!priv->gc) {
485 uint32_t v;
486 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
487
488 v = 0;
489 xcb_create_gc(c,
490 (priv->gc = xcb_generate_id(c)),
491 priv->base.xDrawable,
492 XCB_GC_GRAPHICS_EXPOSURES,
493 &v);
494 }
495 return priv->gc;
496 }
497
498 static struct dri3_buffer *
499 dri3_back_buffer(struct dri3_drawable *priv)
500 {
501 return priv->buffers[DRI3_BACK_ID(priv->cur_back)];
502 }
503
504 static struct dri3_buffer *
505 dri3_fake_front_buffer(struct dri3_drawable *priv)
506 {
507 return priv->buffers[DRI3_FRONT_ID];
508 }
509
510 static void
511 dri3_copy_area (xcb_connection_t *c /**< */,
512 xcb_drawable_t src_drawable /**< */,
513 xcb_drawable_t dst_drawable /**< */,
514 xcb_gcontext_t gc /**< */,
515 int16_t src_x /**< */,
516 int16_t src_y /**< */,
517 int16_t dst_x /**< */,
518 int16_t dst_y /**< */,
519 uint16_t width /**< */,
520 uint16_t height /**< */)
521 {
522 xcb_void_cookie_t cookie;
523
524 cookie = xcb_copy_area_checked(c,
525 src_drawable,
526 dst_drawable,
527 gc,
528 src_x,
529 src_y,
530 dst_x,
531 dst_y,
532 width,
533 height);
534 xcb_discard_reply(c, cookie.sequence);
535 }
536
537 static void
538 dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
539 int width, int height,
540 Bool flush)
541 {
542 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
543 struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
544 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
545 struct dri3_buffer *back = dri3_back_buffer(priv);
546
547 unsigned flags;
548
549 /* Check we have the right attachments */
550 if (!priv->have_back || priv->is_pixmap)
551 return;
552
553 flags = __DRI2_FLUSH_DRAWABLE;
554 if (flush)
555 flags |= __DRI2_FLUSH_CONTEXT;
556 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
557
558 y = priv->height - y - height;
559
560 dri3_fence_reset(c, back);
561 dri3_copy_area(c,
562 dri3_back_buffer(priv)->pixmap,
563 priv->base.xDrawable,
564 dri3_drawable_gc(priv),
565 x, y, x, y, width, height);
566 dri3_fence_trigger(c, back);
567 /* Refresh the fake front (if present) after we just damaged the real
568 * front.
569 */
570 if (priv->have_fake_front) {
571 dri3_fence_reset(c, dri3_fake_front_buffer(priv));
572 dri3_copy_area(c,
573 dri3_back_buffer(priv)->pixmap,
574 dri3_fake_front_buffer(priv)->pixmap,
575 dri3_drawable_gc(priv),
576 x, y, x, y, width, height);
577 dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
578 dri3_fence_await(c, dri3_fake_front_buffer(priv));
579 }
580 dri3_fence_await(c, back);
581 }
582
583 static void
584 dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
585 {
586 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
587 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
588
589 dri3_flush(psc, priv, __DRI2_FLUSH_DRAWABLE, 0);
590
591 dri3_fence_reset(c, dri3_fake_front_buffer(priv));
592 dri3_copy_area(c,
593 src, dest,
594 dri3_drawable_gc(priv),
595 0, 0, 0, 0, priv->width, priv->height);
596 dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
597 dri3_fence_await(c, dri3_fake_front_buffer(priv));
598 }
599
600 static void
601 dri3_wait_x(struct glx_context *gc)
602 {
603 struct dri3_drawable *priv = (struct dri3_drawable *)
604 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
605
606 if (priv == NULL || !priv->have_fake_front)
607 return;
608
609 dri3_copy_drawable(priv, dri3_fake_front_buffer(priv)->pixmap, priv->base.xDrawable);
610 }
611
612 static void
613 dri3_wait_gl(struct glx_context *gc)
614 {
615 struct dri3_drawable *priv = (struct dri3_drawable *)
616 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
617
618 if (priv == NULL || !priv->have_fake_front)
619 return;
620
621 dri3_copy_drawable(priv, priv->base.xDrawable, dri3_fake_front_buffer(priv)->pixmap);
622 }
623
624 /**
625 * Called by the driver when it needs to update the real front buffer with the
626 * contents of its fake front buffer.
627 */
628 static void
629 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
630 {
631 struct glx_context *gc;
632 struct dri3_drawable *pdraw = loaderPrivate;
633 struct dri3_screen *psc;
634
635 if (!pdraw)
636 return;
637
638 if (!pdraw->base.psc)
639 return;
640
641 psc = (struct dri3_screen *) pdraw->base.psc;
642
643 (void) __glXInitialize(psc->base.dpy);
644
645 gc = __glXGetCurrentContext();
646
647 dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
648
649 dri3_wait_gl(gc);
650 }
651
652 static uint32_t
653 dri3_cpp_for_format(uint32_t format) {
654 switch (format) {
655 case __DRI_IMAGE_FORMAT_R8:
656 return 1;
657 case __DRI_IMAGE_FORMAT_RGB565:
658 case __DRI_IMAGE_FORMAT_GR88:
659 return 2;
660 case __DRI_IMAGE_FORMAT_XRGB8888:
661 case __DRI_IMAGE_FORMAT_ARGB8888:
662 case __DRI_IMAGE_FORMAT_ABGR8888:
663 case __DRI_IMAGE_FORMAT_XBGR8888:
664 case __DRI_IMAGE_FORMAT_XRGB2101010:
665 case __DRI_IMAGE_FORMAT_ARGB2101010:
666 case __DRI_IMAGE_FORMAT_SARGB8:
667 return 4;
668 case __DRI_IMAGE_FORMAT_NONE:
669 default:
670 return 0;
671 }
672 }
673
674
675 /** dri3_alloc_render_buffer
676 *
677 * Use the driver createImage function to construct a __DRIimage, then
678 * get a file descriptor for that and create an X pixmap from that
679 *
680 * Allocate an xshmfence for synchronization
681 */
682 static struct dri3_buffer *
683 dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw,
684 unsigned int format, int width, int height, int depth)
685 {
686 struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
687 Display *dpy = glx_screen->dpy;
688 struct dri3_buffer *buffer;
689 xcb_connection_t *c = XGetXCBConnection(dpy);
690 xcb_pixmap_t pixmap;
691 xcb_sync_fence_t sync_fence;
692 struct xshmfence *shm_fence;
693 int buffer_fd, fence_fd;
694 int stride;
695
696 /* Create an xshmfence object and
697 * prepare to send that to the X server
698 */
699
700 fence_fd = xshmfence_alloc_shm();
701 if (fence_fd < 0)
702 return NULL;
703 shm_fence = xshmfence_map_shm(fence_fd);
704 if (shm_fence == NULL)
705 goto no_shm_fence;
706
707 /* Allocate the image from the driver
708 */
709 buffer = calloc(1, sizeof (struct dri3_buffer));
710 if (!buffer)
711 goto no_buffer;
712
713 buffer->cpp = dri3_cpp_for_format(format);
714 if (!buffer->cpp)
715 goto no_image;
716
717 buffer->image = (*psc->image->createImage) (psc->driScreen,
718 width, height,
719 format,
720 __DRI_IMAGE_USE_SHARE|__DRI_IMAGE_USE_SCANOUT,
721 buffer);
722
723
724 if (!buffer->image)
725 goto no_image;
726
727 /* X wants the stride, so ask the image for it
728 */
729 if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride))
730 goto no_buffer_attrib;
731
732 buffer->pitch = stride;
733
734 if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_FD, &buffer_fd))
735 goto no_buffer_attrib;
736
737 xcb_dri3_pixmap_from_buffer(c,
738 (pixmap = xcb_generate_id(c)),
739 draw,
740 buffer->size,
741 width, height, buffer->pitch,
742 depth, buffer->cpp * 8,
743 buffer_fd);
744
745 xcb_dri3_fence_from_fd(c,
746 pixmap,
747 (sync_fence = xcb_generate_id(c)),
748 false,
749 fence_fd);
750
751 buffer->pixmap = pixmap;
752 buffer->own_pixmap = true;
753 buffer->sync_fence = sync_fence;
754 buffer->shm_fence = shm_fence;
755 buffer->width = width;
756 buffer->height = height;
757
758 /* Mark the buffer as idle
759 */
760 dri3_fence_set(buffer);
761
762 return buffer;
763
764 no_buffer_attrib:
765 (*psc->image->destroyImage)(buffer->image);
766 no_image:
767 free(buffer);
768 no_buffer:
769 xshmfence_unmap_shm(shm_fence);
770 no_shm_fence:
771 close(fence_fd);
772 return NULL;
773 }
774
775 /** dri3_free_render_buffer
776 *
777 * Free everything associated with one render buffer including pixmap, fence
778 * stuff and the driver image
779 */
780 static void
781 dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer)
782 {
783 struct dri3_screen *psc = (struct dri3_screen *) pdraw->base.psc;
784 xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy);
785
786 if (buffer->own_pixmap)
787 xcb_free_pixmap(c, buffer->pixmap);
788 xcb_sync_destroy_fence(c, buffer->sync_fence);
789 xshmfence_unmap_shm(buffer->shm_fence);
790 (*psc->image->destroyImage)(buffer->image);
791 free(buffer);
792 }
793
794
795 /** dri3_flush_present_events
796 *
797 * Process any present events that have been received from the X server
798 */
799 static void
800 dri3_flush_present_events(struct dri3_drawable *priv)
801 {
802 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
803
804 /* Check to see if any configuration changes have occurred
805 * since we were last invoked
806 */
807 if (priv->special_event) {
808 xcb_generic_event_t *ev;
809
810 while ((ev = xcb_poll_for_special_event(c, priv->special_event)) != NULL) {
811 xcb_present_generic_event_t *ge = (void *) ev;
812 dri3_handle_present_event(priv, ge);
813 }
814 }
815 }
816
817 /** dri3_update_drawable
818 *
819 * Called the first time we use the drawable and then
820 * after we receive present configure notify events to
821 * track the geometry of the drawable
822 */
823 static int
824 dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
825 {
826 struct dri3_drawable *priv = loaderPrivate;
827 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
828
829 /* First time through, go get the current drawable geometry
830 */
831 if (priv->width == 0 || priv->height == 0 || priv->depth == 0) {
832 xcb_get_geometry_cookie_t geom_cookie;
833 xcb_get_geometry_reply_t *geom_reply;
834 xcb_void_cookie_t cookie;
835 xcb_generic_error_t *error;
836
837 /* Try to select for input on the window.
838 *
839 * If the drawable is a window, this will get our events
840 * delivered.
841 *
842 * Otherwise, we'll get a BadWindow error back from this request which
843 * will let us know that the drawable is a pixmap instead.
844 */
845
846
847 cookie = xcb_present_select_input_checked(c,
848 (priv->eid = xcb_generate_id(c)),
849 priv->base.xDrawable,
850 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
851 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
852 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
853
854 /* Create an XCB event queue to hold present events outside of the usual
855 * application event queue
856 */
857 priv->special_event = xcb_register_for_special_xge(c,
858 &xcb_present_id,
859 priv->eid,
860 priv->stamp);
861
862 geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
863
864 geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
865
866 if (!geom_reply)
867 return false;
868
869 priv->width = geom_reply->width;
870 priv->height = geom_reply->height;
871 priv->depth = geom_reply->depth;
872 priv->is_pixmap = false;
873
874 free(geom_reply);
875
876 /* Check to see if our select input call failed. If it failed with a
877 * BadWindow error, then assume the drawable is a pixmap. Destroy the
878 * special event queue created above and mark the drawable as a pixmap
879 */
880
881 error = xcb_request_check(c, cookie);
882
883 if (error) {
884 if (error->error_code != BadWindow) {
885 free(error);
886 return false;
887 }
888 priv->is_pixmap = true;
889 xcb_unregister_for_special_event(c, priv->special_event);
890 priv->special_event = NULL;
891 }
892 }
893 dri3_flush_present_events(priv);
894 return true;
895 }
896
897 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
898 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
899 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
900 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
901 */
902 static int
903 image_format_to_fourcc(int format)
904 {
905
906 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
907 switch (format) {
908 case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
909 case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
910 case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
911 case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
912 case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
913 }
914 return 0;
915 }
916
917 /** dri3_get_pixmap_buffer
918 *
919 * Get the DRM object for a pixmap from the X server and
920 * wrap that with a __DRIimage structure using createImageFromFds
921 */
922 static struct dri3_buffer *
923 dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
924 unsigned int format,
925 enum dri3_buffer_type buffer_type,
926 void *loaderPrivate)
927 {
928 struct dri3_drawable *pdraw = loaderPrivate;
929 int buf_id = dri3_pixmap_buf_id(buffer_type);
930 struct dri3_buffer *buffer = pdraw->buffers[buf_id];
931 Pixmap pixmap;
932 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
933 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
934 int *fds;
935 Display *dpy;
936 struct dri3_screen *psc;
937 xcb_connection_t *c;
938 xcb_sync_fence_t sync_fence;
939 struct xshmfence *shm_fence;
940 int fence_fd;
941 __DRIimage *image_planar;
942 int stride, offset;
943
944 if (buffer)
945 return buffer;
946
947 pixmap = pdraw->base.xDrawable;
948 psc = (struct dri3_screen *) pdraw->base.psc;
949 dpy = psc->base.dpy;
950 c = XGetXCBConnection(dpy);
951
952 buffer = calloc(1, sizeof (struct dri3_buffer));
953 if (!buffer)
954 goto no_buffer;
955
956 fence_fd = xshmfence_alloc_shm();
957 if (fence_fd < 0)
958 goto no_fence;
959 shm_fence = xshmfence_map_shm(fence_fd);
960 if (shm_fence == NULL) {
961 close (fence_fd);
962 goto no_fence;
963 }
964
965 xcb_dri3_fence_from_fd(c,
966 pixmap,
967 (sync_fence = xcb_generate_id(c)),
968 false,
969 fence_fd);
970
971 /* Get an FD for the pixmap object
972 */
973 bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
974 bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
975 if (!bp_reply)
976 goto no_image;
977 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
978
979 stride = bp_reply->stride;
980 offset = 0;
981
982 /* createImageFromFds creates a wrapper __DRIimage structure which
983 * can deal with multiple planes for things like Yuv images. So, once
984 * we've gotten the planar wrapper, pull the single plane out of it and
985 * discard the wrapper.
986 */
987 image_planar = (*psc->image->createImageFromFds) (psc->driScreen,
988 bp_reply->width,
989 bp_reply->height,
990 image_format_to_fourcc(format),
991 fds, 1,
992 &stride, &offset, buffer);
993 close(fds[0]);
994 if (!image_planar)
995 goto no_image;
996
997 buffer->image = (*psc->image->fromPlanar)(image_planar, 0, buffer);
998
999 (*psc->image->destroyImage)(image_planar);
1000
1001 if (!buffer->image)
1002 goto no_image;
1003
1004 buffer->pixmap = pixmap;
1005 buffer->own_pixmap = false;
1006 buffer->width = bp_reply->width;
1007 buffer->height = bp_reply->height;
1008 buffer->buffer_type = buffer_type;
1009 buffer->shm_fence = shm_fence;
1010 buffer->sync_fence = sync_fence;
1011
1012 pdraw->buffers[buf_id] = buffer;
1013 return buffer;
1014
1015 no_image:
1016 xcb_sync_destroy_fence(c, sync_fence);
1017 xshmfence_unmap_shm(shm_fence);
1018 no_fence:
1019 free(buffer);
1020 no_buffer:
1021 return NULL;
1022 }
1023
1024 /** dri3_find_back
1025 *
1026 * Find an idle back buffer. If there isn't one, then
1027 * wait for a present idle notify event from the X server
1028 */
1029 static int
1030 dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv)
1031 {
1032 int b;
1033 xcb_generic_event_t *ev;
1034 xcb_present_generic_event_t *ge;
1035
1036 for (;;) {
1037
1038 for (b = 0; b < DRI3_NUM_BACK; b++) {
1039 int id = DRI3_BACK_ID(b);
1040 struct dri3_buffer *buffer = priv->buffers[id];
1041
1042 if (!buffer)
1043 return b;
1044 if (!buffer->busy)
1045 return b;
1046 }
1047 ev = xcb_wait_for_special_event(c, priv->special_event);
1048 if (!ev)
1049 return -1;
1050 ge = (void *) ev;
1051 dri3_handle_present_event(priv, ge);
1052 }
1053 }
1054
1055 /** dri3_get_buffer
1056 *
1057 * Find a front or back buffer, allocating new ones as necessary
1058 */
1059 static struct dri3_buffer *
1060 dri3_get_buffer(__DRIdrawable *driDrawable,
1061 unsigned int format,
1062 enum dri3_buffer_type buffer_type,
1063 void *loaderPrivate)
1064 {
1065 struct dri3_drawable *priv = loaderPrivate;
1066 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
1067 struct dri3_buffer *buffer;
1068 int buf_id;
1069
1070 if (buffer_type == dri3_buffer_back) {
1071 int back = dri3_find_back(c, priv);
1072
1073 if (back < 0)
1074 return NULL;
1075
1076 priv->cur_back = back;
1077 buf_id = DRI3_BACK_ID(priv->cur_back);
1078 } else {
1079 buf_id = DRI3_FRONT_ID;
1080 }
1081
1082 buffer = priv->buffers[buf_id];
1083
1084 /* Allocate a new buffer if there isn't an old one, or if that
1085 * old one is the wrong size
1086 */
1087 if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
1088 struct dri3_buffer *new_buffer;
1089
1090 /* Allocate the new buffers
1091 */
1092 new_buffer = dri3_alloc_render_buffer(priv->base.psc,
1093 priv->base.xDrawable,
1094 format, priv->width, priv->height, priv->depth);
1095 if (!new_buffer)
1096 return NULL;
1097
1098 /* When resizing, copy the contents of the old buffer, waiting for that
1099 * copy to complete using our fences before proceeding
1100 */
1101 switch (buffer_type) {
1102 case dri3_buffer_back:
1103 if (buffer) {
1104 dri3_fence_reset(c, new_buffer);
1105 dri3_fence_await(c, buffer);
1106 dri3_copy_area(c,
1107 buffer->pixmap,
1108 new_buffer->pixmap,
1109 dri3_drawable_gc(priv),
1110 0, 0, 0, 0, priv->width, priv->height);
1111 dri3_fence_trigger(c, new_buffer);
1112 dri3_free_render_buffer(priv, buffer);
1113 }
1114 break;
1115 case dri3_buffer_front:
1116 dri3_fence_reset(c, new_buffer);
1117 dri3_copy_area(c,
1118 priv->base.xDrawable,
1119 new_buffer->pixmap,
1120 dri3_drawable_gc(priv),
1121 0, 0, 0, 0, priv->width, priv->height);
1122 dri3_fence_trigger(c, new_buffer);
1123 break;
1124 }
1125 buffer = new_buffer;
1126 buffer->buffer_type = buffer_type;
1127 priv->buffers[buf_id] = buffer;
1128 }
1129 dri3_fence_await(c, buffer);
1130
1131 /* Return the requested buffer */
1132 return buffer;
1133 }
1134
1135 /** dri3_free_buffers
1136 *
1137 * Free the front bufffer or all of the back buffers. Used
1138 * when the application changes which buffers it needs
1139 */
1140 static void
1141 dri3_free_buffers(__DRIdrawable *driDrawable,
1142 enum dri3_buffer_type buffer_type,
1143 void *loaderPrivate)
1144 {
1145 struct dri3_drawable *priv = loaderPrivate;
1146 struct dri3_buffer *buffer;
1147 int first_id;
1148 int n_id;
1149 int buf_id;
1150
1151 switch (buffer_type) {
1152 case dri3_buffer_back:
1153 first_id = DRI3_BACK_ID(0);
1154 n_id = DRI3_NUM_BACK;
1155 break;
1156 case dri3_buffer_front:
1157 first_id = DRI3_FRONT_ID;
1158 n_id = 1;
1159 }
1160
1161 for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {
1162 buffer = priv->buffers[buf_id];
1163 if (buffer) {
1164 dri3_free_render_buffer(priv, buffer);
1165 priv->buffers[buf_id] = NULL;
1166 }
1167 }
1168 }
1169
1170 /** dri3_get_buffers
1171 *
1172 * The published buffer allocation API.
1173 * Returns all of the necessary buffers, allocating
1174 * as needed.
1175 */
1176 static int
1177 dri3_get_buffers(__DRIdrawable *driDrawable,
1178 unsigned int format,
1179 uint32_t *stamp,
1180 void *loaderPrivate,
1181 uint32_t buffer_mask,
1182 struct __DRIimageList *buffers)
1183 {
1184 struct dri3_drawable *priv = loaderPrivate;
1185 struct dri3_buffer *front, *back;
1186
1187 buffers->image_mask = 0;
1188 buffers->front = NULL;
1189 buffers->back = NULL;
1190
1191 front = NULL;
1192 back = NULL;
1193
1194 if (!dri3_update_drawable(driDrawable, loaderPrivate))
1195 return false;
1196
1197 /* pixmaps always have front buffers */
1198 if (priv->is_pixmap)
1199 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
1200
1201 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
1202 if (priv->is_pixmap)
1203 front = dri3_get_pixmap_buffer(driDrawable,
1204 format,
1205 dri3_buffer_front,
1206 loaderPrivate);
1207 else
1208 front = dri3_get_buffer(driDrawable,
1209 format,
1210 dri3_buffer_front,
1211 loaderPrivate);
1212
1213 if (!front)
1214 return false;
1215 } else {
1216 dri3_free_buffers(driDrawable, dri3_buffer_front, loaderPrivate);
1217 priv->have_fake_front = 0;
1218 }
1219
1220 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
1221 back = dri3_get_buffer(driDrawable,
1222 format,
1223 dri3_buffer_back,
1224 loaderPrivate);
1225 if (!back)
1226 return false;
1227 priv->have_back = 1;
1228 } else {
1229 dri3_free_buffers(driDrawable, dri3_buffer_back, loaderPrivate);
1230 priv->have_back = 0;
1231 }
1232
1233 if (front) {
1234 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
1235 buffers->front = front->image;
1236 priv->have_fake_front = !priv->is_pixmap;
1237 }
1238
1239 if (back) {
1240 buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
1241 buffers->back = back->image;
1242 }
1243
1244 priv->stamp = stamp;
1245
1246 return true;
1247 }
1248
1249 /* The image loader extension record for DRI3
1250 */
1251 static const __DRIimageLoaderExtension imageLoaderExtension = {
1252 {__DRI_IMAGE_LOADER, __DRI_IMAGE_LOADER_VERSION},
1253 .getBuffers = dri3_get_buffers,
1254 .flushFrontBuffer = dri3_flush_front_buffer,
1255 };
1256
1257 /** dri3_swap_buffers
1258 *
1259 * Make the current back buffer visible using the present extension
1260 */
1261 static int64_t
1262 dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
1263 int64_t remainder, Bool flush)
1264 {
1265 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1266 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1267 Display *dpy = priv->base.psc->dpy;
1268 xcb_connection_t *c = XGetXCBConnection(dpy);
1269 int buf_id = DRI3_BACK_ID(priv->cur_back);
1270 int64_t ret = 0;
1271
1272 unsigned flags = __DRI2_FLUSH_DRAWABLE;
1273 if (flush)
1274 flags |= __DRI2_FLUSH_CONTEXT;
1275 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
1276
1277 dri3_flush_present_events(priv);
1278
1279 if (priv->buffers[buf_id] && !priv->is_pixmap) {
1280 dri3_fence_reset(c, priv->buffers[buf_id]);
1281
1282 /* Compute when we want the frame shown by taking the last known successful
1283 * MSC and adding in a swap interval for each outstanding swap request
1284 */
1285 ++priv->present_request_serial;
1286 if (target_msc == 0)
1287 target_msc = priv->msc + priv->swap_interval * (priv->present_request_serial - priv->present_event_serial);
1288
1289 priv->buffers[buf_id]->busy = 1;
1290 xcb_present_pixmap(c,
1291 priv->base.xDrawable,
1292 priv->buffers[buf_id]->pixmap,
1293 priv->present_request_serial,
1294 0, /* valid */
1295 0, /* update */
1296 0, /* x_off */
1297 0, /* y_off */
1298 None, /* target_crtc */
1299 None,
1300 priv->buffers[buf_id]->sync_fence,
1301 XCB_PRESENT_OPTION_NONE,
1302 target_msc,
1303 divisor,
1304 remainder, 0, NULL);
1305 ret = ++priv->sbc;
1306
1307 /* If there's a fake front, then copy the source back buffer
1308 * to the fake front to keep it up to date. This needs
1309 * to reset the fence and make future users block until
1310 * the X server is done copying the bits
1311 */
1312 if (priv->have_fake_front) {
1313 dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]);
1314 dri3_copy_area(c,
1315 priv->buffers[buf_id]->pixmap,
1316 priv->buffers[DRI3_FRONT_ID]->pixmap,
1317 dri3_drawable_gc(priv),
1318 0, 0, 0, 0, priv->width, priv->height);
1319 dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]);
1320 }
1321 xcb_flush(c);
1322 if (priv->stamp)
1323 ++(*priv->stamp);
1324 }
1325
1326 return ret;
1327 }
1328
1329 /** dri3_open
1330 *
1331 * Wrapper around xcb_dri3_open
1332 */
1333 static int
1334 dri3_open(Display *dpy,
1335 Window root,
1336 CARD32 provider)
1337 {
1338 xcb_dri3_open_cookie_t cookie;
1339 xcb_dri3_open_reply_t *reply;
1340 xcb_connection_t *c = XGetXCBConnection(dpy);
1341 int fd;
1342
1343 cookie = xcb_dri3_open(c,
1344 root,
1345 provider);
1346
1347 reply = xcb_dri3_open_reply(c, cookie, NULL);
1348 if (!reply)
1349 return -1;
1350
1351 if (reply->nfd != 1) {
1352 free(reply);
1353 return -1;
1354 }
1355
1356 fd = xcb_dri3_open_reply_fds(c, reply)[0];
1357 fcntl(fd, F_SETFD, FD_CLOEXEC);
1358
1359 return fd;
1360 }
1361
1362
1363 /** dri3_destroy_screen
1364 */
1365 static void
1366 dri3_destroy_screen(struct glx_screen *base)
1367 {
1368 struct dri3_screen *psc = (struct dri3_screen *) base;
1369
1370 /* Free the direct rendering per screen data */
1371 (*psc->core->destroyScreen) (psc->driScreen);
1372 driDestroyConfigs(psc->driver_configs);
1373 close(psc->fd);
1374 free(psc);
1375 }
1376
1377 /** dri3_set_swap_interval
1378 *
1379 * Record the application swap interval specification,
1380 */
1381 static int
1382 dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
1383 {
1384 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1385 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1386 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1387
1388 if (psc->config)
1389 psc->config->configQueryi(psc->driScreen,
1390 "vblank_mode", &vblank_mode);
1391
1392 switch (vblank_mode) {
1393 case DRI_CONF_VBLANK_NEVER:
1394 if (interval != 0)
1395 return GLX_BAD_VALUE;
1396 break;
1397 case DRI_CONF_VBLANK_ALWAYS_SYNC:
1398 if (interval <= 0)
1399 return GLX_BAD_VALUE;
1400 break;
1401 default:
1402 break;
1403 }
1404
1405 priv->swap_interval = interval;
1406
1407 return 0;
1408 }
1409
1410 /** dri3_get_swap_interval
1411 *
1412 * Return the stored swap interval
1413 */
1414 static int
1415 dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
1416 {
1417 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1418
1419 return priv->swap_interval;
1420 }
1421
1422 static void
1423 dri3_bind_tex_image(Display * dpy,
1424 GLXDrawable drawable,
1425 int buffer, const int *attrib_list)
1426 {
1427 struct glx_context *gc = __glXGetCurrentContext();
1428 struct dri3_context *pcp = (struct dri3_context *) gc;
1429 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1430 struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1431 struct dri3_screen *psc;
1432
1433 if (pdraw != NULL) {
1434 psc = (struct dri3_screen *) base->psc;
1435
1436 (*psc->f->invalidate)(pdraw->driDrawable);
1437
1438 XSync(dpy, false);
1439
1440 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
1441 pdraw->base.textureTarget,
1442 pdraw->base.textureFormat,
1443 pdraw->driDrawable);
1444 }
1445 }
1446
1447 static void
1448 dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
1449 {
1450 struct glx_context *gc = __glXGetCurrentContext();
1451 struct dri3_context *pcp = (struct dri3_context *) gc;
1452 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1453 struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1454 struct dri3_screen *psc;
1455
1456 if (pdraw != NULL) {
1457 psc = (struct dri3_screen *) base->psc;
1458
1459 if (psc->texBuffer->releaseTexBuffer)
1460 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
1461 pdraw->base.textureTarget,
1462 pdraw->driDrawable);
1463 }
1464 }
1465
1466 static const struct glx_context_vtable dri3_context_vtable = {
1467 dri3_destroy_context,
1468 dri3_bind_context,
1469 dri3_unbind_context,
1470 dri3_wait_gl,
1471 dri3_wait_x,
1472 DRI_glXUseXFont,
1473 dri3_bind_tex_image,
1474 dri3_release_tex_image,
1475 NULL, /* get_proc_address */
1476 };
1477
1478 /** dri3_bind_extensions
1479 *
1480 * Enable all of the extensions supported on DRI3
1481 */
1482 static void
1483 dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
1484 const char *driverName)
1485 {
1486 const __DRIextension **extensions;
1487 unsigned mask;
1488 int i;
1489
1490 extensions = psc->core->getExtensions(psc->driScreen);
1491
1492 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
1493 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
1494 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
1495 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
1496
1497 /*
1498 * GLX_INTEL_swap_event is broken on the server side, where it's
1499 * currently unconditionally enabled. This completely breaks
1500 * systems running on drivers which don't support that extension.
1501 * There's no way to test for its presence on this side, so instead
1502 * of disabling it unconditionally, just disable it for drivers
1503 * which are known to not support it, or for DDX drivers supporting
1504 * only an older (pre-ScheduleSwap) version of DRI2.
1505 *
1506 * This is a hack which is required until:
1507 * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
1508 * is merged and updated xserver makes it's way into distros:
1509 */
1510 // if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
1511 // __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1512 // }
1513
1514 mask = psc->image_driver->getAPIMask(psc->driScreen);
1515
1516 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
1517 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
1518
1519 if ((mask & (1 << __DRI_API_GLES2)) != 0)
1520 __glXEnableDirectExtension(&psc->base,
1521 "GLX_EXT_create_context_es2_profile");
1522
1523 for (i = 0; extensions[i]; i++) {
1524 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
1525 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
1526 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
1527 }
1528
1529 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
1530 psc->f = (__DRI2flushExtension *) extensions[i];
1531 /* internal driver extension, no GL extension exposed */
1532 }
1533
1534 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
1535 psc->config = (__DRI2configQueryExtension *) extensions[i];
1536
1537 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1538 __glXEnableDirectExtension(&psc->base,
1539 "GLX_ARB_create_context_robustness");
1540 }
1541 }
1542
1543 static const struct glx_screen_vtable dri3_screen_vtable = {
1544 dri3_create_context,
1545 dri3_create_context_attribs
1546 };
1547
1548 /** dri3_create_screen
1549 *
1550 * Initialize DRI3 on the specified screen.
1551 *
1552 * Opens the DRI device, locates the appropriate DRI driver
1553 * and loads that.
1554 *
1555 * Checks to see if the driver supports the necessary extensions
1556 *
1557 * Initializes the driver for the screen and sets up our structures
1558 */
1559
1560 static struct glx_screen *
1561 dri3_create_screen(int screen, struct glx_display * priv)
1562 {
1563 xcb_connection_t *c = XGetXCBConnection(priv->dpy);
1564 const __DRIconfig **driver_configs;
1565 const __DRIextension **extensions;
1566 const struct dri3_display *const pdp = (struct dri3_display *)
1567 priv->dri3Display;
1568 struct dri3_screen *psc;
1569 __GLXDRIscreen *psp;
1570 struct glx_config *configs = NULL, *visuals = NULL;
1571 char *driverName, *deviceName;
1572 int i;
1573
1574 psc = calloc(1, sizeof *psc);
1575 if (psc == NULL)
1576 return NULL;
1577
1578 psc->fd = -1;
1579
1580 if (!glx_screen_init(&psc->base, screen, priv)) {
1581 free(psc);
1582 return NULL;
1583 }
1584
1585 psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
1586 if (psc->fd < 0) {
1587 int conn_error = xcb_connection_has_error(c);
1588
1589 glx_screen_cleanup(&psc->base);
1590 free(psc);
1591 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
1592
1593 if (conn_error)
1594 ErrorMessageF("Connection closed during DRI3 initialization failure");
1595
1596 return NULL;
1597 }
1598 deviceName = NULL;
1599
1600 driverName = loader_get_driver_for_fd(psc->fd, 0);
1601 if (!driverName) {
1602 ErrorMessageF("No driver found\n");
1603 goto handle_error;
1604 }
1605
1606 psc->driver = driOpenDriver(driverName);
1607 if (psc->driver == NULL) {
1608 ErrorMessageF("driver pointer missing\n");
1609 goto handle_error;
1610 }
1611
1612 extensions = driGetDriverExtensions(psc->driver, driverName);
1613 if (extensions == NULL)
1614 goto handle_error;
1615
1616 for (i = 0; extensions[i]; i++) {
1617 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1618 psc->core = (__DRIcoreExtension *) extensions[i];
1619 if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0)
1620 psc->image_driver = (__DRIimageDriverExtension *) extensions[i];
1621 }
1622
1623
1624 if (psc->core == NULL) {
1625 ErrorMessageF("core dri driver extension not found\n");
1626 goto handle_error;
1627 }
1628
1629 if (psc->image_driver == NULL) {
1630 ErrorMessageF("image driver extension not found\n");
1631 goto handle_error;
1632 }
1633
1634 psc->driScreen =
1635 psc->image_driver->createNewScreen2(screen, psc->fd,
1636 (const __DRIextension **)
1637 &pdp->loader_extensions[0],
1638 extensions,
1639 &driver_configs, psc);
1640
1641 if (psc->driScreen == NULL) {
1642 ErrorMessageF("failed to create dri screen\n");
1643 goto handle_error;
1644 }
1645
1646 extensions = (*psc->core->getExtensions)(psc->driScreen);
1647
1648 for (i = 0; extensions[i]; i++) {
1649 if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0)
1650 psc->image = (__DRIimageExtension *) extensions[i];
1651 }
1652
1653 if (psc->image == NULL) {
1654 ErrorMessageF("image extension not found\n");
1655 goto handle_error;
1656 }
1657
1658 dri3_bind_extensions(psc, priv, driverName);
1659
1660 if (!psc->f || psc->f->base.version < 4) {
1661 ErrorMessageF("Version 4 or later of flush extension not found\n");
1662 goto handle_error;
1663 }
1664
1665 if (!psc->texBuffer || psc->texBuffer->base.version < 2 ||
1666 !psc->texBuffer->setTexBuffer2)
1667 {
1668 ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
1669 goto handle_error;
1670 }
1671
1672 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1673 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1674
1675 if (!configs || !visuals)
1676 goto handle_error;
1677
1678 glx_config_destroy_list(psc->base.configs);
1679 psc->base.configs = configs;
1680 glx_config_destroy_list(psc->base.visuals);
1681 psc->base.visuals = visuals;
1682
1683 psc->driver_configs = driver_configs;
1684
1685 psc->base.vtable = &dri3_screen_vtable;
1686 psp = &psc->vtable;
1687 psc->base.driScreen = psp;
1688 psp->destroyScreen = dri3_destroy_screen;
1689 psp->createDrawable = dri3_create_drawable;
1690 psp->swapBuffers = dri3_swap_buffers;
1691
1692 psp->getDrawableMSC = dri3_drawable_get_msc;
1693 psp->waitForMSC = dri3_wait_for_msc;
1694 psp->waitForSBC = dri3_wait_for_sbc;
1695 psp->setSwapInterval = dri3_set_swap_interval;
1696 psp->getSwapInterval = dri3_get_swap_interval;
1697 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1698
1699 psp->copySubBuffer = dri3_copy_sub_buffer;
1700 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1701
1702 free(driverName);
1703 free(deviceName);
1704
1705 return &psc->base;
1706
1707 handle_error:
1708 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1709
1710 if (configs)
1711 glx_config_destroy_list(configs);
1712 if (visuals)
1713 glx_config_destroy_list(visuals);
1714 if (psc->driScreen)
1715 psc->core->destroyScreen(psc->driScreen);
1716 psc->driScreen = NULL;
1717 if (psc->fd >= 0)
1718 close(psc->fd);
1719 if (psc->driver)
1720 dlclose(psc->driver);
1721
1722 free(driverName);
1723 free(deviceName);
1724 glx_screen_cleanup(&psc->base);
1725 free(psc);
1726
1727 return NULL;
1728 }
1729
1730 /** dri_destroy_display
1731 *
1732 * Called from __glXFreeDisplayPrivate.
1733 */
1734 static void
1735 dri3_destroy_display(__GLXDRIdisplay * dpy)
1736 {
1737 free(dpy);
1738 }
1739
1740 /** dri3_create_display
1741 *
1742 * Allocate, initialize and return a __DRIdisplayPrivate object.
1743 * This is called from __glXInitialize() when we are given a new
1744 * display pointer. This is public to that function, but hidden from
1745 * outside of libGL.
1746 */
1747 _X_HIDDEN __GLXDRIdisplay *
1748 dri3_create_display(Display * dpy)
1749 {
1750 struct dri3_display *pdp;
1751 int i;
1752 xcb_connection_t *c = XGetXCBConnection(dpy);
1753 xcb_dri3_query_version_cookie_t dri3_cookie;
1754 xcb_dri3_query_version_reply_t *dri3_reply;
1755 xcb_present_query_version_cookie_t present_cookie;
1756 xcb_present_query_version_reply_t *present_reply;
1757 xcb_generic_error_t *error;
1758 const xcb_query_extension_reply_t *extension;
1759
1760 xcb_prefetch_extension_data(c, &xcb_dri3_id);
1761 xcb_prefetch_extension_data(c, &xcb_present_id);
1762
1763 extension = xcb_get_extension_data(c, &xcb_dri3_id);
1764 if (!(extension && extension->present))
1765 return NULL;
1766
1767 extension = xcb_get_extension_data(c, &xcb_present_id);
1768 if (!(extension && extension->present))
1769 return NULL;
1770
1771 dri3_cookie = xcb_dri3_query_version(c,
1772 XCB_DRI3_MAJOR_VERSION,
1773 XCB_DRI3_MINOR_VERSION);
1774
1775
1776 present_cookie = xcb_present_query_version(c,
1777 XCB_PRESENT_MAJOR_VERSION,
1778 XCB_PRESENT_MINOR_VERSION);
1779
1780 pdp = malloc(sizeof *pdp);
1781 if (pdp == NULL)
1782 return NULL;
1783
1784 dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error);
1785 if (!dri3_reply) {
1786 free(error);
1787 goto no_extension;
1788 }
1789
1790 pdp->dri3Major = dri3_reply->major_version;
1791 pdp->dri3Minor = dri3_reply->minor_version;
1792 free(dri3_reply);
1793
1794 present_reply = xcb_present_query_version_reply(c, present_cookie, &error);
1795 if (!present_reply) {
1796 free(error);
1797 goto no_extension;
1798 }
1799 pdp->presentMajor = present_reply->major_version;
1800 pdp->presentMinor = present_reply->minor_version;
1801 free(present_reply);
1802
1803 pdp->base.destroyDisplay = dri3_destroy_display;
1804 pdp->base.createScreen = dri3_create_screen;
1805
1806 loader_set_logger(ErrorMessageF);
1807 i = 0;
1808
1809 pdp->loader_extensions[i++] = &imageLoaderExtension.base;
1810
1811 pdp->loader_extensions[i++] = &systemTimeExtension.base;
1812
1813 pdp->loader_extensions[i++] = NULL;
1814
1815 return &pdp->base;
1816 no_extension:
1817 free(pdp);
1818 return NULL;
1819 }
1820
1821 #endif /* GLX_DIRECT_RENDERING */