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