dri3: Flush XCB before blocking for special events
[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 /* Compute the processed SBC number from the received 32-bit serial number merged
369 * with the upper 32-bits of the sent 64-bit serial number while checking for
370 * wrap
371 */
372 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
373 priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial;
374 if (priv->recv_sbc > priv->send_sbc)
375 priv->recv_sbc -= 0x100000000;
376 } else {
377 priv->recv_msc_serial = ce->serial;
378 }
379 priv->ust = ce->ust;
380 priv->msc = ce->msc;
381 break;
382 }
383 case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
384 xcb_present_idle_notify_event_t *ie = (void *) ge;
385 int b;
386
387 for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) {
388 struct dri3_buffer *buf = priv->buffers[b];
389
390 if (buf && buf->pixmap == ie->pixmap) {
391 buf->busy = 0;
392 break;
393 }
394 }
395 break;
396 }
397 }
398 free(ge);
399 }
400
401 static bool
402 dri3_wait_for_event(__GLXDRIdrawable *pdraw)
403 {
404 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
405 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
406 xcb_generic_event_t *ev;
407 xcb_present_generic_event_t *ge;
408
409 xcb_flush(c);
410 ev = xcb_wait_for_special_event(c, priv->special_event);
411 if (!ev)
412 return false;
413 ge = (void *) ev;
414 dri3_handle_present_event(priv, ge);
415 return true;
416 }
417
418 /** dri3_wait_for_msc
419 *
420 * Get the X server to send an event when the target msc/divisor/remainder is
421 * reached.
422 */
423 static int
424 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
425 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
426 {
427 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
428 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
429 uint32_t msc_serial;
430
431 /* Ask for the an event for the target MSC */
432 msc_serial = ++priv->send_msc_serial;
433 xcb_present_notify_msc(c,
434 priv->base.xDrawable,
435 msc_serial,
436 target_msc,
437 divisor,
438 remainder);
439
440 xcb_flush(c);
441
442 /* Wait for the event */
443 if (priv->special_event) {
444 while ((int32_t) (msc_serial - priv->recv_msc_serial) > 0) {
445 if (!dri3_wait_for_event(pdraw))
446 return 0;
447 }
448 }
449
450 *ust = priv->ust;
451 *msc = priv->msc;
452 *sbc = priv->recv_sbc;
453
454 return 1;
455 }
456
457 /** dri3_drawable_get_msc
458 *
459 * Return the current UST/MSC/SBC triplet by asking the server
460 * for an event
461 */
462 static int
463 dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
464 int64_t *ust, int64_t *msc, int64_t *sbc)
465 {
466 return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
467 }
468
469 /** dri3_wait_for_sbc
470 *
471 * Wait for the completed swap buffer count to reach the specified
472 * target. Presumably the application knows that this will be reached with
473 * outstanding complete events, or we're going to be here awhile.
474 */
475 static int
476 dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
477 int64_t *msc, int64_t *sbc)
478 {
479 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
480
481 while (priv->recv_sbc < target_sbc) {
482 if (!dri3_wait_for_event(pdraw))
483 return 0;
484 }
485
486 *ust = priv->ust;
487 *msc = priv->msc;
488 *sbc = priv->recv_sbc;
489 return 1;
490 }
491
492 /**
493 * Asks the driver to flush any queued work necessary for serializing with the
494 * X command stream, and optionally the slightly more strict requirement of
495 * glFlush() equivalence (which would require flushing even if nothing had
496 * been drawn to a window system framebuffer, for example).
497 */
498 static void
499 dri3_flush(struct dri3_screen *psc,
500 struct dri3_drawable *draw,
501 unsigned flags,
502 enum __DRI2throttleReason throttle_reason)
503 {
504 struct glx_context *gc = __glXGetCurrentContext();
505
506 if (gc) {
507 struct dri3_context *dri3Ctx = (struct dri3_context *)gc;
508
509 (*psc->f->flush_with_flags)(dri3Ctx->driContext, draw->driDrawable, flags, throttle_reason);
510 }
511 }
512
513 static xcb_gcontext_t
514 dri3_drawable_gc(struct dri3_drawable *priv)
515 {
516 if (!priv->gc) {
517 uint32_t v;
518 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
519
520 v = 0;
521 xcb_create_gc(c,
522 (priv->gc = xcb_generate_id(c)),
523 priv->base.xDrawable,
524 XCB_GC_GRAPHICS_EXPOSURES,
525 &v);
526 }
527 return priv->gc;
528 }
529
530 static struct dri3_buffer *
531 dri3_back_buffer(struct dri3_drawable *priv)
532 {
533 return priv->buffers[DRI3_BACK_ID(priv->cur_back)];
534 }
535
536 static struct dri3_buffer *
537 dri3_fake_front_buffer(struct dri3_drawable *priv)
538 {
539 return priv->buffers[DRI3_FRONT_ID];
540 }
541
542 static void
543 dri3_copy_area (xcb_connection_t *c /**< */,
544 xcb_drawable_t src_drawable /**< */,
545 xcb_drawable_t dst_drawable /**< */,
546 xcb_gcontext_t gc /**< */,
547 int16_t src_x /**< */,
548 int16_t src_y /**< */,
549 int16_t dst_x /**< */,
550 int16_t dst_y /**< */,
551 uint16_t width /**< */,
552 uint16_t height /**< */)
553 {
554 xcb_void_cookie_t cookie;
555
556 cookie = xcb_copy_area_checked(c,
557 src_drawable,
558 dst_drawable,
559 gc,
560 src_x,
561 src_y,
562 dst_x,
563 dst_y,
564 width,
565 height);
566 xcb_discard_reply(c, cookie.sequence);
567 }
568
569 static void
570 dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
571 int width, int height,
572 Bool flush)
573 {
574 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
575 struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
576 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
577 struct dri3_buffer *back = dri3_back_buffer(priv);
578
579 unsigned flags;
580
581 /* Check we have the right attachments */
582 if (!priv->have_back || priv->is_pixmap)
583 return;
584
585 flags = __DRI2_FLUSH_DRAWABLE;
586 if (flush)
587 flags |= __DRI2_FLUSH_CONTEXT;
588 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
589
590 y = priv->height - y - height;
591
592 dri3_fence_reset(c, back);
593 dri3_copy_area(c,
594 dri3_back_buffer(priv)->pixmap,
595 priv->base.xDrawable,
596 dri3_drawable_gc(priv),
597 x, y, x, y, width, height);
598 dri3_fence_trigger(c, back);
599 /* Refresh the fake front (if present) after we just damaged the real
600 * front.
601 */
602 if (priv->have_fake_front) {
603 dri3_fence_reset(c, dri3_fake_front_buffer(priv));
604 dri3_copy_area(c,
605 dri3_back_buffer(priv)->pixmap,
606 dri3_fake_front_buffer(priv)->pixmap,
607 dri3_drawable_gc(priv),
608 x, y, x, y, width, height);
609 dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
610 dri3_fence_await(c, dri3_fake_front_buffer(priv));
611 }
612 dri3_fence_await(c, back);
613 }
614
615 static void
616 dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
617 {
618 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
619 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
620
621 dri3_flush(psc, priv, __DRI2_FLUSH_DRAWABLE, 0);
622
623 dri3_fence_reset(c, dri3_fake_front_buffer(priv));
624 dri3_copy_area(c,
625 src, dest,
626 dri3_drawable_gc(priv),
627 0, 0, 0, 0, priv->width, priv->height);
628 dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
629 dri3_fence_await(c, dri3_fake_front_buffer(priv));
630 }
631
632 static void
633 dri3_wait_x(struct glx_context *gc)
634 {
635 struct dri3_drawable *priv = (struct dri3_drawable *)
636 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
637
638 if (priv == NULL || !priv->have_fake_front)
639 return;
640
641 dri3_copy_drawable(priv, dri3_fake_front_buffer(priv)->pixmap, priv->base.xDrawable);
642 }
643
644 static void
645 dri3_wait_gl(struct glx_context *gc)
646 {
647 struct dri3_drawable *priv = (struct dri3_drawable *)
648 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
649
650 if (priv == NULL || !priv->have_fake_front)
651 return;
652
653 dri3_copy_drawable(priv, priv->base.xDrawable, dri3_fake_front_buffer(priv)->pixmap);
654 }
655
656 /**
657 * Called by the driver when it needs to update the real front buffer with the
658 * contents of its fake front buffer.
659 */
660 static void
661 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
662 {
663 struct glx_context *gc;
664 struct dri3_drawable *pdraw = loaderPrivate;
665 struct dri3_screen *psc;
666
667 if (!pdraw)
668 return;
669
670 if (!pdraw->base.psc)
671 return;
672
673 psc = (struct dri3_screen *) pdraw->base.psc;
674
675 (void) __glXInitialize(psc->base.dpy);
676
677 gc = __glXGetCurrentContext();
678
679 dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
680
681 dri3_wait_gl(gc);
682 }
683
684 static uint32_t
685 dri3_cpp_for_format(uint32_t format) {
686 switch (format) {
687 case __DRI_IMAGE_FORMAT_R8:
688 return 1;
689 case __DRI_IMAGE_FORMAT_RGB565:
690 case __DRI_IMAGE_FORMAT_GR88:
691 return 2;
692 case __DRI_IMAGE_FORMAT_XRGB8888:
693 case __DRI_IMAGE_FORMAT_ARGB8888:
694 case __DRI_IMAGE_FORMAT_ABGR8888:
695 case __DRI_IMAGE_FORMAT_XBGR8888:
696 case __DRI_IMAGE_FORMAT_XRGB2101010:
697 case __DRI_IMAGE_FORMAT_ARGB2101010:
698 case __DRI_IMAGE_FORMAT_SARGB8:
699 return 4;
700 case __DRI_IMAGE_FORMAT_NONE:
701 default:
702 return 0;
703 }
704 }
705
706
707 /** dri3_alloc_render_buffer
708 *
709 * Use the driver createImage function to construct a __DRIimage, then
710 * get a file descriptor for that and create an X pixmap from that
711 *
712 * Allocate an xshmfence for synchronization
713 */
714 static struct dri3_buffer *
715 dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw,
716 unsigned int format, int width, int height, int depth)
717 {
718 struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
719 Display *dpy = glx_screen->dpy;
720 struct dri3_buffer *buffer;
721 xcb_connection_t *c = XGetXCBConnection(dpy);
722 xcb_pixmap_t pixmap;
723 xcb_sync_fence_t sync_fence;
724 struct xshmfence *shm_fence;
725 int buffer_fd, fence_fd;
726 int stride;
727
728 /* Create an xshmfence object and
729 * prepare to send that to the X server
730 */
731
732 fence_fd = xshmfence_alloc_shm();
733 if (fence_fd < 0)
734 return NULL;
735 shm_fence = xshmfence_map_shm(fence_fd);
736 if (shm_fence == NULL)
737 goto no_shm_fence;
738
739 /* Allocate the image from the driver
740 */
741 buffer = calloc(1, sizeof (struct dri3_buffer));
742 if (!buffer)
743 goto no_buffer;
744
745 buffer->cpp = dri3_cpp_for_format(format);
746 if (!buffer->cpp)
747 goto no_image;
748
749 buffer->image = (*psc->image->createImage) (psc->driScreen,
750 width, height,
751 format,
752 __DRI_IMAGE_USE_SHARE|__DRI_IMAGE_USE_SCANOUT,
753 buffer);
754
755
756 if (!buffer->image)
757 goto no_image;
758
759 /* X wants the stride, so ask the image for it
760 */
761 if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride))
762 goto no_buffer_attrib;
763
764 buffer->pitch = stride;
765
766 if (!(*psc->image->queryImage)(buffer->image, __DRI_IMAGE_ATTRIB_FD, &buffer_fd))
767 goto no_buffer_attrib;
768
769 xcb_dri3_pixmap_from_buffer(c,
770 (pixmap = xcb_generate_id(c)),
771 draw,
772 buffer->size,
773 width, height, buffer->pitch,
774 depth, buffer->cpp * 8,
775 buffer_fd);
776
777 xcb_dri3_fence_from_fd(c,
778 pixmap,
779 (sync_fence = xcb_generate_id(c)),
780 false,
781 fence_fd);
782
783 buffer->pixmap = pixmap;
784 buffer->own_pixmap = true;
785 buffer->sync_fence = sync_fence;
786 buffer->shm_fence = shm_fence;
787 buffer->width = width;
788 buffer->height = height;
789
790 /* Mark the buffer as idle
791 */
792 dri3_fence_set(buffer);
793
794 return buffer;
795
796 no_buffer_attrib:
797 (*psc->image->destroyImage)(buffer->image);
798 no_image:
799 free(buffer);
800 no_buffer:
801 xshmfence_unmap_shm(shm_fence);
802 no_shm_fence:
803 close(fence_fd);
804 return NULL;
805 }
806
807 /** dri3_free_render_buffer
808 *
809 * Free everything associated with one render buffer including pixmap, fence
810 * stuff and the driver image
811 */
812 static void
813 dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer)
814 {
815 struct dri3_screen *psc = (struct dri3_screen *) pdraw->base.psc;
816 xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy);
817
818 if (buffer->own_pixmap)
819 xcb_free_pixmap(c, buffer->pixmap);
820 xcb_sync_destroy_fence(c, buffer->sync_fence);
821 xshmfence_unmap_shm(buffer->shm_fence);
822 (*psc->image->destroyImage)(buffer->image);
823 free(buffer);
824 }
825
826
827 /** dri3_flush_present_events
828 *
829 * Process any present events that have been received from the X server
830 */
831 static void
832 dri3_flush_present_events(struct dri3_drawable *priv)
833 {
834 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
835
836 /* Check to see if any configuration changes have occurred
837 * since we were last invoked
838 */
839 if (priv->special_event) {
840 xcb_generic_event_t *ev;
841
842 while ((ev = xcb_poll_for_special_event(c, priv->special_event)) != NULL) {
843 xcb_present_generic_event_t *ge = (void *) ev;
844 dri3_handle_present_event(priv, ge);
845 }
846 }
847 }
848
849 /** dri3_update_drawable
850 *
851 * Called the first time we use the drawable and then
852 * after we receive present configure notify events to
853 * track the geometry of the drawable
854 */
855 static int
856 dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
857 {
858 struct dri3_drawable *priv = loaderPrivate;
859 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
860
861 /* First time through, go get the current drawable geometry
862 */
863 if (priv->width == 0 || priv->height == 0 || priv->depth == 0) {
864 xcb_get_geometry_cookie_t geom_cookie;
865 xcb_get_geometry_reply_t *geom_reply;
866 xcb_void_cookie_t cookie;
867 xcb_generic_error_t *error;
868
869 /* Try to select for input on the window.
870 *
871 * If the drawable is a window, this will get our events
872 * delivered.
873 *
874 * Otherwise, we'll get a BadWindow error back from this request which
875 * will let us know that the drawable is a pixmap instead.
876 */
877
878
879 cookie = xcb_present_select_input_checked(c,
880 (priv->eid = xcb_generate_id(c)),
881 priv->base.xDrawable,
882 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
883 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
884 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
885
886 /* Create an XCB event queue to hold present events outside of the usual
887 * application event queue
888 */
889 priv->special_event = xcb_register_for_special_xge(c,
890 &xcb_present_id,
891 priv->eid,
892 priv->stamp);
893
894 geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
895
896 geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
897
898 if (!geom_reply)
899 return false;
900
901 priv->width = geom_reply->width;
902 priv->height = geom_reply->height;
903 priv->depth = geom_reply->depth;
904 priv->is_pixmap = false;
905
906 free(geom_reply);
907
908 /* Check to see if our select input call failed. If it failed with a
909 * BadWindow error, then assume the drawable is a pixmap. Destroy the
910 * special event queue created above and mark the drawable as a pixmap
911 */
912
913 error = xcb_request_check(c, cookie);
914
915 if (error) {
916 if (error->error_code != BadWindow) {
917 free(error);
918 return false;
919 }
920 priv->is_pixmap = true;
921 xcb_unregister_for_special_event(c, priv->special_event);
922 priv->special_event = NULL;
923 }
924 }
925 dri3_flush_present_events(priv);
926 return true;
927 }
928
929 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
930 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
931 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
932 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
933 */
934 static int
935 image_format_to_fourcc(int format)
936 {
937
938 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
939 switch (format) {
940 case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
941 case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
942 case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
943 case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
944 case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
945 }
946 return 0;
947 }
948
949 /** dri3_get_pixmap_buffer
950 *
951 * Get the DRM object for a pixmap from the X server and
952 * wrap that with a __DRIimage structure using createImageFromFds
953 */
954 static struct dri3_buffer *
955 dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
956 unsigned int format,
957 enum dri3_buffer_type buffer_type,
958 void *loaderPrivate)
959 {
960 struct dri3_drawable *pdraw = loaderPrivate;
961 int buf_id = dri3_pixmap_buf_id(buffer_type);
962 struct dri3_buffer *buffer = pdraw->buffers[buf_id];
963 Pixmap pixmap;
964 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
965 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
966 int *fds;
967 Display *dpy;
968 struct dri3_screen *psc;
969 xcb_connection_t *c;
970 xcb_sync_fence_t sync_fence;
971 struct xshmfence *shm_fence;
972 int fence_fd;
973 __DRIimage *image_planar;
974 int stride, offset;
975
976 if (buffer)
977 return buffer;
978
979 pixmap = pdraw->base.xDrawable;
980 psc = (struct dri3_screen *) pdraw->base.psc;
981 dpy = psc->base.dpy;
982 c = XGetXCBConnection(dpy);
983
984 buffer = calloc(1, sizeof (struct dri3_buffer));
985 if (!buffer)
986 goto no_buffer;
987
988 fence_fd = xshmfence_alloc_shm();
989 if (fence_fd < 0)
990 goto no_fence;
991 shm_fence = xshmfence_map_shm(fence_fd);
992 if (shm_fence == NULL) {
993 close (fence_fd);
994 goto no_fence;
995 }
996
997 xcb_dri3_fence_from_fd(c,
998 pixmap,
999 (sync_fence = xcb_generate_id(c)),
1000 false,
1001 fence_fd);
1002
1003 /* Get an FD for the pixmap object
1004 */
1005 bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
1006 bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
1007 if (!bp_reply)
1008 goto no_image;
1009 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
1010
1011 stride = bp_reply->stride;
1012 offset = 0;
1013
1014 /* createImageFromFds creates a wrapper __DRIimage structure which
1015 * can deal with multiple planes for things like Yuv images. So, once
1016 * we've gotten the planar wrapper, pull the single plane out of it and
1017 * discard the wrapper.
1018 */
1019 image_planar = (*psc->image->createImageFromFds) (psc->driScreen,
1020 bp_reply->width,
1021 bp_reply->height,
1022 image_format_to_fourcc(format),
1023 fds, 1,
1024 &stride, &offset, buffer);
1025 close(fds[0]);
1026 if (!image_planar)
1027 goto no_image;
1028
1029 buffer->image = (*psc->image->fromPlanar)(image_planar, 0, buffer);
1030
1031 (*psc->image->destroyImage)(image_planar);
1032
1033 if (!buffer->image)
1034 goto no_image;
1035
1036 buffer->pixmap = pixmap;
1037 buffer->own_pixmap = false;
1038 buffer->width = bp_reply->width;
1039 buffer->height = bp_reply->height;
1040 buffer->buffer_type = buffer_type;
1041 buffer->shm_fence = shm_fence;
1042 buffer->sync_fence = sync_fence;
1043
1044 pdraw->buffers[buf_id] = buffer;
1045 return buffer;
1046
1047 no_image:
1048 xcb_sync_destroy_fence(c, sync_fence);
1049 xshmfence_unmap_shm(shm_fence);
1050 no_fence:
1051 free(buffer);
1052 no_buffer:
1053 return NULL;
1054 }
1055
1056 /** dri3_find_back
1057 *
1058 * Find an idle back buffer. If there isn't one, then
1059 * wait for a present idle notify event from the X server
1060 */
1061 static int
1062 dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv)
1063 {
1064 int b;
1065 xcb_generic_event_t *ev;
1066 xcb_present_generic_event_t *ge;
1067
1068 for (;;) {
1069
1070 for (b = 0; b < DRI3_NUM_BACK; b++) {
1071 int id = DRI3_BACK_ID(b);
1072 struct dri3_buffer *buffer = priv->buffers[id];
1073
1074 if (!buffer)
1075 return b;
1076 if (!buffer->busy)
1077 return b;
1078 }
1079 xcb_flush(c);
1080 ev = xcb_wait_for_special_event(c, priv->special_event);
1081 if (!ev)
1082 return -1;
1083 ge = (void *) ev;
1084 dri3_handle_present_event(priv, ge);
1085 }
1086 }
1087
1088 /** dri3_get_buffer
1089 *
1090 * Find a front or back buffer, allocating new ones as necessary
1091 */
1092 static struct dri3_buffer *
1093 dri3_get_buffer(__DRIdrawable *driDrawable,
1094 unsigned int format,
1095 enum dri3_buffer_type buffer_type,
1096 void *loaderPrivate)
1097 {
1098 struct dri3_drawable *priv = loaderPrivate;
1099 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
1100 struct dri3_buffer *buffer;
1101 int buf_id;
1102
1103 if (buffer_type == dri3_buffer_back) {
1104 int back = dri3_find_back(c, priv);
1105
1106 if (back < 0)
1107 return NULL;
1108
1109 priv->cur_back = back;
1110 buf_id = DRI3_BACK_ID(priv->cur_back);
1111 } else {
1112 buf_id = DRI3_FRONT_ID;
1113 }
1114
1115 buffer = priv->buffers[buf_id];
1116
1117 /* Allocate a new buffer if there isn't an old one, or if that
1118 * old one is the wrong size
1119 */
1120 if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
1121 struct dri3_buffer *new_buffer;
1122
1123 /* Allocate the new buffers
1124 */
1125 new_buffer = dri3_alloc_render_buffer(priv->base.psc,
1126 priv->base.xDrawable,
1127 format, priv->width, priv->height, priv->depth);
1128 if (!new_buffer)
1129 return NULL;
1130
1131 /* When resizing, copy the contents of the old buffer, waiting for that
1132 * copy to complete using our fences before proceeding
1133 */
1134 switch (buffer_type) {
1135 case dri3_buffer_back:
1136 if (buffer) {
1137 dri3_fence_reset(c, new_buffer);
1138 dri3_fence_await(c, buffer);
1139 dri3_copy_area(c,
1140 buffer->pixmap,
1141 new_buffer->pixmap,
1142 dri3_drawable_gc(priv),
1143 0, 0, 0, 0, priv->width, priv->height);
1144 dri3_fence_trigger(c, new_buffer);
1145 dri3_free_render_buffer(priv, buffer);
1146 }
1147 break;
1148 case dri3_buffer_front:
1149 dri3_fence_reset(c, new_buffer);
1150 dri3_copy_area(c,
1151 priv->base.xDrawable,
1152 new_buffer->pixmap,
1153 dri3_drawable_gc(priv),
1154 0, 0, 0, 0, priv->width, priv->height);
1155 dri3_fence_trigger(c, new_buffer);
1156 break;
1157 }
1158 buffer = new_buffer;
1159 buffer->buffer_type = buffer_type;
1160 priv->buffers[buf_id] = buffer;
1161 }
1162 dri3_fence_await(c, buffer);
1163
1164 /* Return the requested buffer */
1165 return buffer;
1166 }
1167
1168 /** dri3_free_buffers
1169 *
1170 * Free the front bufffer or all of the back buffers. Used
1171 * when the application changes which buffers it needs
1172 */
1173 static void
1174 dri3_free_buffers(__DRIdrawable *driDrawable,
1175 enum dri3_buffer_type buffer_type,
1176 void *loaderPrivate)
1177 {
1178 struct dri3_drawable *priv = loaderPrivate;
1179 struct dri3_buffer *buffer;
1180 int first_id;
1181 int n_id;
1182 int buf_id;
1183
1184 switch (buffer_type) {
1185 case dri3_buffer_back:
1186 first_id = DRI3_BACK_ID(0);
1187 n_id = DRI3_NUM_BACK;
1188 break;
1189 case dri3_buffer_front:
1190 first_id = DRI3_FRONT_ID;
1191 n_id = 1;
1192 }
1193
1194 for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {
1195 buffer = priv->buffers[buf_id];
1196 if (buffer) {
1197 dri3_free_render_buffer(priv, buffer);
1198 priv->buffers[buf_id] = NULL;
1199 }
1200 }
1201 }
1202
1203 /** dri3_get_buffers
1204 *
1205 * The published buffer allocation API.
1206 * Returns all of the necessary buffers, allocating
1207 * as needed.
1208 */
1209 static int
1210 dri3_get_buffers(__DRIdrawable *driDrawable,
1211 unsigned int format,
1212 uint32_t *stamp,
1213 void *loaderPrivate,
1214 uint32_t buffer_mask,
1215 struct __DRIimageList *buffers)
1216 {
1217 struct dri3_drawable *priv = loaderPrivate;
1218 struct dri3_buffer *front, *back;
1219
1220 buffers->image_mask = 0;
1221 buffers->front = NULL;
1222 buffers->back = NULL;
1223
1224 front = NULL;
1225 back = NULL;
1226
1227 if (!dri3_update_drawable(driDrawable, loaderPrivate))
1228 return false;
1229
1230 /* pixmaps always have front buffers */
1231 if (priv->is_pixmap)
1232 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
1233
1234 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
1235 if (priv->is_pixmap)
1236 front = dri3_get_pixmap_buffer(driDrawable,
1237 format,
1238 dri3_buffer_front,
1239 loaderPrivate);
1240 else
1241 front = dri3_get_buffer(driDrawable,
1242 format,
1243 dri3_buffer_front,
1244 loaderPrivate);
1245
1246 if (!front)
1247 return false;
1248 } else {
1249 dri3_free_buffers(driDrawable, dri3_buffer_front, loaderPrivate);
1250 priv->have_fake_front = 0;
1251 }
1252
1253 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
1254 back = dri3_get_buffer(driDrawable,
1255 format,
1256 dri3_buffer_back,
1257 loaderPrivate);
1258 if (!back)
1259 return false;
1260 priv->have_back = 1;
1261 } else {
1262 dri3_free_buffers(driDrawable, dri3_buffer_back, loaderPrivate);
1263 priv->have_back = 0;
1264 }
1265
1266 if (front) {
1267 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
1268 buffers->front = front->image;
1269 priv->have_fake_front = !priv->is_pixmap;
1270 }
1271
1272 if (back) {
1273 buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
1274 buffers->back = back->image;
1275 }
1276
1277 priv->stamp = stamp;
1278
1279 return true;
1280 }
1281
1282 /* The image loader extension record for DRI3
1283 */
1284 static const __DRIimageLoaderExtension imageLoaderExtension = {
1285 {__DRI_IMAGE_LOADER, __DRI_IMAGE_LOADER_VERSION},
1286 .getBuffers = dri3_get_buffers,
1287 .flushFrontBuffer = dri3_flush_front_buffer,
1288 };
1289
1290 /** dri3_swap_buffers
1291 *
1292 * Make the current back buffer visible using the present extension
1293 */
1294 static int64_t
1295 dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
1296 int64_t remainder, Bool flush)
1297 {
1298 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1299 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1300 Display *dpy = priv->base.psc->dpy;
1301 xcb_connection_t *c = XGetXCBConnection(dpy);
1302 int buf_id = DRI3_BACK_ID(priv->cur_back);
1303 int64_t ret = 0;
1304
1305 unsigned flags = __DRI2_FLUSH_DRAWABLE;
1306 if (flush)
1307 flags |= __DRI2_FLUSH_CONTEXT;
1308 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
1309
1310 dri3_flush_present_events(priv);
1311
1312 if (priv->buffers[buf_id] && !priv->is_pixmap) {
1313 dri3_fence_reset(c, priv->buffers[buf_id]);
1314
1315 /* Compute when we want the frame shown by taking the last known successful
1316 * MSC and adding in a swap interval for each outstanding swap request
1317 */
1318 ++priv->send_sbc;
1319 if (target_msc == 0)
1320 target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc);
1321
1322 priv->buffers[buf_id]->busy = 1;
1323 xcb_present_pixmap(c,
1324 priv->base.xDrawable,
1325 priv->buffers[buf_id]->pixmap,
1326 (uint32_t) priv->send_sbc,
1327 0, /* valid */
1328 0, /* update */
1329 0, /* x_off */
1330 0, /* y_off */
1331 None, /* target_crtc */
1332 None,
1333 priv->buffers[buf_id]->sync_fence,
1334 XCB_PRESENT_OPTION_NONE,
1335 target_msc,
1336 divisor,
1337 remainder, 0, NULL);
1338 ret = (int64_t) priv->send_sbc;
1339
1340 /* If there's a fake front, then copy the source back buffer
1341 * to the fake front to keep it up to date. This needs
1342 * to reset the fence and make future users block until
1343 * the X server is done copying the bits
1344 */
1345 if (priv->have_fake_front) {
1346 dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]);
1347 dri3_copy_area(c,
1348 priv->buffers[buf_id]->pixmap,
1349 priv->buffers[DRI3_FRONT_ID]->pixmap,
1350 dri3_drawable_gc(priv),
1351 0, 0, 0, 0, priv->width, priv->height);
1352 dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]);
1353 }
1354 xcb_flush(c);
1355 if (priv->stamp)
1356 ++(*priv->stamp);
1357 }
1358
1359 return ret;
1360 }
1361
1362 /** dri3_open
1363 *
1364 * Wrapper around xcb_dri3_open
1365 */
1366 static int
1367 dri3_open(Display *dpy,
1368 Window root,
1369 CARD32 provider)
1370 {
1371 xcb_dri3_open_cookie_t cookie;
1372 xcb_dri3_open_reply_t *reply;
1373 xcb_connection_t *c = XGetXCBConnection(dpy);
1374 int fd;
1375
1376 cookie = xcb_dri3_open(c,
1377 root,
1378 provider);
1379
1380 reply = xcb_dri3_open_reply(c, cookie, NULL);
1381 if (!reply)
1382 return -1;
1383
1384 if (reply->nfd != 1) {
1385 free(reply);
1386 return -1;
1387 }
1388
1389 fd = xcb_dri3_open_reply_fds(c, reply)[0];
1390 fcntl(fd, F_SETFD, FD_CLOEXEC);
1391
1392 return fd;
1393 }
1394
1395
1396 /** dri3_destroy_screen
1397 */
1398 static void
1399 dri3_destroy_screen(struct glx_screen *base)
1400 {
1401 struct dri3_screen *psc = (struct dri3_screen *) base;
1402
1403 /* Free the direct rendering per screen data */
1404 (*psc->core->destroyScreen) (psc->driScreen);
1405 driDestroyConfigs(psc->driver_configs);
1406 close(psc->fd);
1407 free(psc);
1408 }
1409
1410 /** dri3_set_swap_interval
1411 *
1412 * Record the application swap interval specification,
1413 */
1414 static int
1415 dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
1416 {
1417 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1418 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1419 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1420
1421 if (psc->config)
1422 psc->config->configQueryi(psc->driScreen,
1423 "vblank_mode", &vblank_mode);
1424
1425 switch (vblank_mode) {
1426 case DRI_CONF_VBLANK_NEVER:
1427 if (interval != 0)
1428 return GLX_BAD_VALUE;
1429 break;
1430 case DRI_CONF_VBLANK_ALWAYS_SYNC:
1431 if (interval <= 0)
1432 return GLX_BAD_VALUE;
1433 break;
1434 default:
1435 break;
1436 }
1437
1438 priv->swap_interval = interval;
1439
1440 return 0;
1441 }
1442
1443 /** dri3_get_swap_interval
1444 *
1445 * Return the stored swap interval
1446 */
1447 static int
1448 dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
1449 {
1450 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1451
1452 return priv->swap_interval;
1453 }
1454
1455 static void
1456 dri3_bind_tex_image(Display * dpy,
1457 GLXDrawable drawable,
1458 int buffer, const int *attrib_list)
1459 {
1460 struct glx_context *gc = __glXGetCurrentContext();
1461 struct dri3_context *pcp = (struct dri3_context *) gc;
1462 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1463 struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1464 struct dri3_screen *psc;
1465
1466 if (pdraw != NULL) {
1467 psc = (struct dri3_screen *) base->psc;
1468
1469 (*psc->f->invalidate)(pdraw->driDrawable);
1470
1471 XSync(dpy, false);
1472
1473 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
1474 pdraw->base.textureTarget,
1475 pdraw->base.textureFormat,
1476 pdraw->driDrawable);
1477 }
1478 }
1479
1480 static void
1481 dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
1482 {
1483 struct glx_context *gc = __glXGetCurrentContext();
1484 struct dri3_context *pcp = (struct dri3_context *) gc;
1485 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1486 struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1487 struct dri3_screen *psc;
1488
1489 if (pdraw != NULL) {
1490 psc = (struct dri3_screen *) base->psc;
1491
1492 if (psc->texBuffer->releaseTexBuffer)
1493 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
1494 pdraw->base.textureTarget,
1495 pdraw->driDrawable);
1496 }
1497 }
1498
1499 static const struct glx_context_vtable dri3_context_vtable = {
1500 dri3_destroy_context,
1501 dri3_bind_context,
1502 dri3_unbind_context,
1503 dri3_wait_gl,
1504 dri3_wait_x,
1505 DRI_glXUseXFont,
1506 dri3_bind_tex_image,
1507 dri3_release_tex_image,
1508 NULL, /* get_proc_address */
1509 };
1510
1511 /** dri3_bind_extensions
1512 *
1513 * Enable all of the extensions supported on DRI3
1514 */
1515 static void
1516 dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
1517 const char *driverName)
1518 {
1519 const __DRIextension **extensions;
1520 unsigned mask;
1521 int i;
1522
1523 extensions = psc->core->getExtensions(psc->driScreen);
1524
1525 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
1526 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
1527 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
1528 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
1529 __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1530
1531 mask = psc->image_driver->getAPIMask(psc->driScreen);
1532
1533 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
1534 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
1535
1536 if ((mask & (1 << __DRI_API_GLES2)) != 0)
1537 __glXEnableDirectExtension(&psc->base,
1538 "GLX_EXT_create_context_es2_profile");
1539
1540 for (i = 0; extensions[i]; i++) {
1541 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
1542 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
1543 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
1544 }
1545
1546 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
1547 psc->f = (__DRI2flushExtension *) extensions[i];
1548 /* internal driver extension, no GL extension exposed */
1549 }
1550
1551 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
1552 psc->config = (__DRI2configQueryExtension *) extensions[i];
1553
1554 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1555 __glXEnableDirectExtension(&psc->base,
1556 "GLX_ARB_create_context_robustness");
1557 }
1558 }
1559
1560 static const struct glx_screen_vtable dri3_screen_vtable = {
1561 dri3_create_context,
1562 dri3_create_context_attribs
1563 };
1564
1565 /** dri3_create_screen
1566 *
1567 * Initialize DRI3 on the specified screen.
1568 *
1569 * Opens the DRI device, locates the appropriate DRI driver
1570 * and loads that.
1571 *
1572 * Checks to see if the driver supports the necessary extensions
1573 *
1574 * Initializes the driver for the screen and sets up our structures
1575 */
1576
1577 static struct glx_screen *
1578 dri3_create_screen(int screen, struct glx_display * priv)
1579 {
1580 xcb_connection_t *c = XGetXCBConnection(priv->dpy);
1581 const __DRIconfig **driver_configs;
1582 const __DRIextension **extensions;
1583 const struct dri3_display *const pdp = (struct dri3_display *)
1584 priv->dri3Display;
1585 struct dri3_screen *psc;
1586 __GLXDRIscreen *psp;
1587 struct glx_config *configs = NULL, *visuals = NULL;
1588 char *driverName, *deviceName;
1589 int i;
1590
1591 psc = calloc(1, sizeof *psc);
1592 if (psc == NULL)
1593 return NULL;
1594
1595 psc->fd = -1;
1596
1597 if (!glx_screen_init(&psc->base, screen, priv)) {
1598 free(psc);
1599 return NULL;
1600 }
1601
1602 psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
1603 if (psc->fd < 0) {
1604 int conn_error = xcb_connection_has_error(c);
1605
1606 glx_screen_cleanup(&psc->base);
1607 free(psc);
1608 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
1609
1610 if (conn_error)
1611 ErrorMessageF("Connection closed during DRI3 initialization failure");
1612
1613 return NULL;
1614 }
1615 deviceName = NULL;
1616
1617 driverName = loader_get_driver_for_fd(psc->fd, 0);
1618 if (!driverName) {
1619 ErrorMessageF("No driver found\n");
1620 goto handle_error;
1621 }
1622
1623 psc->driver = driOpenDriver(driverName);
1624 if (psc->driver == NULL) {
1625 ErrorMessageF("driver pointer missing\n");
1626 goto handle_error;
1627 }
1628
1629 extensions = driGetDriverExtensions(psc->driver, driverName);
1630 if (extensions == NULL)
1631 goto handle_error;
1632
1633 for (i = 0; extensions[i]; i++) {
1634 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1635 psc->core = (__DRIcoreExtension *) extensions[i];
1636 if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0)
1637 psc->image_driver = (__DRIimageDriverExtension *) extensions[i];
1638 }
1639
1640
1641 if (psc->core == NULL) {
1642 ErrorMessageF("core dri driver extension not found\n");
1643 goto handle_error;
1644 }
1645
1646 if (psc->image_driver == NULL) {
1647 ErrorMessageF("image driver extension not found\n");
1648 goto handle_error;
1649 }
1650
1651 psc->driScreen =
1652 psc->image_driver->createNewScreen2(screen, psc->fd,
1653 (const __DRIextension **)
1654 &pdp->loader_extensions[0],
1655 extensions,
1656 &driver_configs, psc);
1657
1658 if (psc->driScreen == NULL) {
1659 ErrorMessageF("failed to create dri screen\n");
1660 goto handle_error;
1661 }
1662
1663 extensions = (*psc->core->getExtensions)(psc->driScreen);
1664
1665 for (i = 0; extensions[i]; i++) {
1666 if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0)
1667 psc->image = (__DRIimageExtension *) extensions[i];
1668 }
1669
1670 if (psc->image == NULL) {
1671 ErrorMessageF("image extension not found\n");
1672 goto handle_error;
1673 }
1674
1675 dri3_bind_extensions(psc, priv, driverName);
1676
1677 if (!psc->f || psc->f->base.version < 4) {
1678 ErrorMessageF("Version 4 or later of flush extension not found\n");
1679 goto handle_error;
1680 }
1681
1682 if (!psc->texBuffer || psc->texBuffer->base.version < 2 ||
1683 !psc->texBuffer->setTexBuffer2)
1684 {
1685 ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
1686 goto handle_error;
1687 }
1688
1689 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1690 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1691
1692 if (!configs || !visuals)
1693 goto handle_error;
1694
1695 glx_config_destroy_list(psc->base.configs);
1696 psc->base.configs = configs;
1697 glx_config_destroy_list(psc->base.visuals);
1698 psc->base.visuals = visuals;
1699
1700 psc->driver_configs = driver_configs;
1701
1702 psc->base.vtable = &dri3_screen_vtable;
1703 psp = &psc->vtable;
1704 psc->base.driScreen = psp;
1705 psp->destroyScreen = dri3_destroy_screen;
1706 psp->createDrawable = dri3_create_drawable;
1707 psp->swapBuffers = dri3_swap_buffers;
1708
1709 psp->getDrawableMSC = dri3_drawable_get_msc;
1710 psp->waitForMSC = dri3_wait_for_msc;
1711 psp->waitForSBC = dri3_wait_for_sbc;
1712 psp->setSwapInterval = dri3_set_swap_interval;
1713 psp->getSwapInterval = dri3_get_swap_interval;
1714 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1715
1716 psp->copySubBuffer = dri3_copy_sub_buffer;
1717 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1718
1719 free(driverName);
1720 free(deviceName);
1721
1722 return &psc->base;
1723
1724 handle_error:
1725 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1726
1727 if (configs)
1728 glx_config_destroy_list(configs);
1729 if (visuals)
1730 glx_config_destroy_list(visuals);
1731 if (psc->driScreen)
1732 psc->core->destroyScreen(psc->driScreen);
1733 psc->driScreen = NULL;
1734 if (psc->fd >= 0)
1735 close(psc->fd);
1736 if (psc->driver)
1737 dlclose(psc->driver);
1738
1739 free(driverName);
1740 free(deviceName);
1741 glx_screen_cleanup(&psc->base);
1742 free(psc);
1743
1744 return NULL;
1745 }
1746
1747 /** dri_destroy_display
1748 *
1749 * Called from __glXFreeDisplayPrivate.
1750 */
1751 static void
1752 dri3_destroy_display(__GLXDRIdisplay * dpy)
1753 {
1754 free(dpy);
1755 }
1756
1757 /** dri3_create_display
1758 *
1759 * Allocate, initialize and return a __DRIdisplayPrivate object.
1760 * This is called from __glXInitialize() when we are given a new
1761 * display pointer. This is public to that function, but hidden from
1762 * outside of libGL.
1763 */
1764 _X_HIDDEN __GLXDRIdisplay *
1765 dri3_create_display(Display * dpy)
1766 {
1767 struct dri3_display *pdp;
1768 int i;
1769 xcb_connection_t *c = XGetXCBConnection(dpy);
1770 xcb_dri3_query_version_cookie_t dri3_cookie;
1771 xcb_dri3_query_version_reply_t *dri3_reply;
1772 xcb_present_query_version_cookie_t present_cookie;
1773 xcb_present_query_version_reply_t *present_reply;
1774 xcb_generic_error_t *error;
1775 const xcb_query_extension_reply_t *extension;
1776
1777 xcb_prefetch_extension_data(c, &xcb_dri3_id);
1778 xcb_prefetch_extension_data(c, &xcb_present_id);
1779
1780 extension = xcb_get_extension_data(c, &xcb_dri3_id);
1781 if (!(extension && extension->present))
1782 return NULL;
1783
1784 extension = xcb_get_extension_data(c, &xcb_present_id);
1785 if (!(extension && extension->present))
1786 return NULL;
1787
1788 dri3_cookie = xcb_dri3_query_version(c,
1789 XCB_DRI3_MAJOR_VERSION,
1790 XCB_DRI3_MINOR_VERSION);
1791
1792
1793 present_cookie = xcb_present_query_version(c,
1794 XCB_PRESENT_MAJOR_VERSION,
1795 XCB_PRESENT_MINOR_VERSION);
1796
1797 pdp = malloc(sizeof *pdp);
1798 if (pdp == NULL)
1799 return NULL;
1800
1801 dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error);
1802 if (!dri3_reply) {
1803 free(error);
1804 goto no_extension;
1805 }
1806
1807 pdp->dri3Major = dri3_reply->major_version;
1808 pdp->dri3Minor = dri3_reply->minor_version;
1809 free(dri3_reply);
1810
1811 present_reply = xcb_present_query_version_reply(c, present_cookie, &error);
1812 if (!present_reply) {
1813 free(error);
1814 goto no_extension;
1815 }
1816 pdp->presentMajor = present_reply->major_version;
1817 pdp->presentMinor = present_reply->minor_version;
1818 free(present_reply);
1819
1820 pdp->base.destroyDisplay = dri3_destroy_display;
1821 pdp->base.createScreen = dri3_create_screen;
1822
1823 loader_set_logger(dri_message);
1824 i = 0;
1825
1826 pdp->loader_extensions[i++] = &imageLoaderExtension.base;
1827
1828 pdp->loader_extensions[i++] = &systemTimeExtension.base;
1829
1830 pdp->loader_extensions[i++] = NULL;
1831
1832 return &pdp->base;
1833 no_extension:
1834 free(pdp);
1835 return NULL;
1836 }
1837
1838 #endif /* GLX_DIRECT_RENDERING */