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