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