1 /*
2  * Copyright © 2015 Boyan Ding
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 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include <xcb/xcb.h>
29 #include <xcb/dri3.h>
30 #include <xcb/present.h>
31 #include <xcb/xfixes.h>
32 
33 #include <xf86drm.h>
34 #include "util/macros.h"
35 
36 #include "egl_dri2.h"
37 #include "platform_x11_dri3.h"
38 
39 #include "loader.h"
40 #include "loader_dri3_helper.h"
41 
42 static struct dri3_egl_surface *
loader_drawable_to_egl_surface(struct loader_dri3_drawable * draw)43 loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {
44    size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
45    return (struct dri3_egl_surface *)(((void*) draw) - offset);
46 }
47 
48 static void
egl_dri3_set_drawable_size(struct loader_dri3_drawable * draw,int width,int height)49 egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
50                            int width, int height)
51 {
52    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
53 
54    dri3_surf->surf.base.Width = width;
55    dri3_surf->surf.base.Height = height;
56 }
57 
58 static bool
egl_dri3_in_current_context(struct loader_dri3_drawable * draw)59 egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
60 {
61    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
62    _EGLContext *ctx = _eglGetCurrentContext();
63 
64    return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
65 }
66 
67 static __DRIcontext *
egl_dri3_get_dri_context(struct loader_dri3_drawable * draw)68 egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
69 {
70    _EGLContext *ctx = _eglGetCurrentContext();
71    struct dri2_egl_context *dri2_ctx;
72    if (!ctx)
73       return NULL;
74    dri2_ctx = dri2_egl_context(ctx);
75    return dri2_ctx->dri_context;
76 }
77 
78 static __DRIscreen *
egl_dri3_get_dri_screen(void)79 egl_dri3_get_dri_screen(void)
80 {
81    _EGLContext *ctx = _eglGetCurrentContext();
82    struct dri2_egl_context *dri2_ctx;
83    if (!ctx)
84       return NULL;
85    dri2_ctx = dri2_egl_context(ctx);
86    return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;
87 }
88 
89 static void
egl_dri3_flush_drawable(struct loader_dri3_drawable * draw,unsigned flags)90 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
91 {
92    struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
93    _EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
94 
95    dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
96 }
97 
98 static const struct loader_dri3_vtable egl_dri3_vtable = {
99    .set_drawable_size = egl_dri3_set_drawable_size,
100    .in_current_context = egl_dri3_in_current_context,
101    .get_dri_context = egl_dri3_get_dri_context,
102    .get_dri_screen = egl_dri3_get_dri_screen,
103    .flush_drawable = egl_dri3_flush_drawable,
104    .show_fps = NULL,
105 };
106 
107 static EGLBoolean
dri3_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)108 dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
109 {
110    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
111    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
112    xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
113 
114    loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
115 
116    if (surf->Type == EGL_PBUFFER_BIT)
117       xcb_free_pixmap (dri2_dpy->conn, drawable);
118 
119    dri2_fini_surface(surf);
120    free(surf);
121 
122    return EGL_TRUE;
123 }
124 
125 static EGLBoolean
dri3_set_swap_interval(_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)126 dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
127 {
128    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
129 
130    dri3_surf->surf.base.SwapInterval = interval;
131    loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
132 
133    return EGL_TRUE;
134 }
135 
136 static _EGLSurface *
dri3_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)137 dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
138                     void *native_surface, const EGLint *attrib_list)
139 {
140    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
141    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
142    struct dri3_egl_surface *dri3_surf;
143    const __DRIconfig *dri_config;
144    xcb_drawable_t drawable;
145 
146    dri3_surf = calloc(1, sizeof *dri3_surf);
147    if (!dri3_surf) {
148       _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
149       return NULL;
150    }
151 
152    if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
153                           attrib_list, false, native_surface))
154       goto cleanup_surf;
155 
156    if (type == EGL_PBUFFER_BIT) {
157       drawable = xcb_generate_id(dri2_dpy->conn);
158       xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
159                         drawable, dri2_dpy->screen->root,
160                         dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
161    } else {
162       STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
163       drawable = (uintptr_t) native_surface;
164    }
165 
166    dri_config = dri2_get_dri_config(dri2_conf, type,
167                                     dri3_surf->surf.base.GLColorspace);
168 
169    if (!dri_config) {
170       _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
171       goto cleanup_pixmap;
172    }
173 
174    if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
175                                  dri2_dpy->dri_screen,
176                                  dri2_dpy->is_different_gpu,
177                                  dri2_dpy->multibuffers_available,
178                                  true,
179                                  dri_config,
180                                  &dri2_dpy->loader_dri3_ext,
181                                  &egl_dri3_vtable,
182                                  &dri3_surf->loader_drawable)) {
183       _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
184       goto cleanup_pixmap;
185    }
186 
187    if (dri3_surf->surf.base.ProtectedContent &&
188        dri2_dpy->is_different_gpu) {
189       _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
190       goto cleanup_pixmap;
191    }
192 
193    dri3_surf->loader_drawable.is_protected_content =
194       dri3_surf->surf.base.ProtectedContent;
195 
196    return &dri3_surf->surf.base;
197 
198  cleanup_pixmap:
199    if (type == EGL_PBUFFER_BIT)
200       xcb_free_pixmap(dri2_dpy->conn, drawable);
201  cleanup_surf:
202    free(dri3_surf);
203 
204    return NULL;
205 }
206 
207 static int
dri3_authenticate(_EGLDisplay * disp,uint32_t id)208 dri3_authenticate(_EGLDisplay *disp, uint32_t id)
209 {
210 #ifdef HAVE_WAYLAND_PLATFORM
211    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
212 
213    if (dri2_dpy->device_name) {
214       _eglLog(_EGL_WARNING,
215               "Wayland client render node authentication is unnecessary");
216       return 0;
217    }
218 
219    _eglLog(_EGL_WARNING,
220            "Wayland client primary node authentication isn't supported");
221 #endif
222 
223    return -1;
224 }
225 
226 /**
227  * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
228  */
229 static _EGLSurface *
dri3_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)230 dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
231                            void *native_window, const EGLint *attrib_list)
232 {
233    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
234    _EGLSurface *surf;
235 
236    surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
237                               native_window, attrib_list);
238    if (surf != NULL)
239       dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
240 
241    return surf;
242 }
243 
244 static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)245 dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
246                            void *native_pixmap, const EGLint *attrib_list)
247 {
248    return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf,
249                               native_pixmap, attrib_list);
250 }
251 
252 static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)253 dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
254                             const EGLint *attrib_list)
255 {
256    return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
257                               NULL, attrib_list);
258 }
259 
260 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)261 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
262                      EGLuint64KHR *ust, EGLuint64KHR *msc,
263                      EGLuint64KHR *sbc)
264 {
265    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
266 
267    return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
268                                    (int64_t *) ust, (int64_t *) msc,
269                                    (int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
270 }
271 
272 static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)273 dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
274                              EGLClientBuffer buffer, const EGLint *attr_list)
275 {
276    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
277    struct dri2_egl_image *dri2_img;
278    xcb_drawable_t drawable;
279    xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
280    xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
281    unsigned int format;
282 
283    drawable = (xcb_drawable_t) (uintptr_t) buffer;
284    bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
285    bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
286                                                 bp_cookie, NULL);
287    if (!bp_reply) {
288       _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
289       return NULL;
290    }
291 
292    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
293    if (format == __DRI_IMAGE_FORMAT_NONE) {
294       _eglError(EGL_BAD_PARAMETER,
295                 "dri3_create_image_khr: unsupported pixmap depth");
296       free(bp_reply);
297       return EGL_NO_IMAGE_KHR;
298    }
299 
300    dri2_img = malloc(sizeof *dri2_img);
301    if (!dri2_img) {
302       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
303       free(bp_reply);
304       return EGL_NO_IMAGE_KHR;
305    }
306 
307    _eglInitImage(&dri2_img->base, disp);
308 
309    dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
310                                                   bp_reply,
311                                                   format,
312                                                   dri2_dpy->dri_screen,
313                                                   dri2_dpy->image,
314                                                   dri2_img);
315 
316    free(bp_reply);
317 
318    return &dri2_img->base;
319 }
320 
321 #ifdef HAVE_DRI3_MODIFIERS
322 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)323 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
324                                           EGLClientBuffer buffer,
325                                           const EGLint *attr_list)
326 {
327    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
328    struct dri2_egl_image *dri2_img;
329    xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
330    xcb_dri3_buffers_from_pixmap_reply_t  *bp_reply;
331    xcb_drawable_t drawable;
332    unsigned int format;
333 
334    drawable = (xcb_drawable_t) (uintptr_t) buffer;
335    bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
336    bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
337                                                  bp_cookie, NULL);
338 
339    if (!bp_reply) {
340       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
341       return EGL_NO_IMAGE_KHR;
342    }
343 
344    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
345    if (format == __DRI_IMAGE_FORMAT_NONE) {
346       _eglError(EGL_BAD_PARAMETER,
347                 "dri3_create_image_khr: unsupported pixmap depth");
348       free(bp_reply);
349       return EGL_NO_IMAGE_KHR;
350    }
351 
352    dri2_img = malloc(sizeof *dri2_img);
353    if (!dri2_img) {
354       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
355       free(bp_reply);
356       return EGL_NO_IMAGE_KHR;
357    }
358 
359    _eglInitImage(&dri2_img->base, disp);
360 
361    dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
362                                                                bp_reply,
363                                                                format,
364                                                                dri2_dpy->dri_screen,
365                                                                dri2_dpy->image,
366                                                                dri2_img);
367    free(bp_reply);
368 
369    if (!dri2_img->dri_image) {
370       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
371       free(dri2_img);
372       return EGL_NO_IMAGE_KHR;
373    }
374 
375    return &dri2_img->base;
376 }
377 #endif
378 
379 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)380 dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
381                       EGLClientBuffer buffer, const EGLint *attr_list)
382 {
383 #ifdef HAVE_DRI3_MODIFIERS
384    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
385 #endif
386 
387    switch (target) {
388    case EGL_NATIVE_PIXMAP_KHR:
389 #ifdef HAVE_DRI3_MODIFIERS
390       if (dri2_dpy->multibuffers_available)
391          return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
392                                                           attr_list);
393 #endif
394       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
395    default:
396       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
397    }
398 }
399 
400 /**
401  * Called by the driver when it needs to update the real front buffer with the
402  * contents of its fake front buffer.
403  */
404 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)405 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
406 {
407    struct loader_dri3_drawable *draw = loaderPrivate;
408    (void) driDrawable;
409 
410    /* There does not seem to be any kind of consensus on whether we should
411     * support front-buffer rendering or not:
412     * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
413     */
414    if (!draw->is_pixmap)
415       _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
416 }
417 
418 const __DRIimageLoaderExtension dri3_image_loader_extension = {
419    .base = { __DRI_IMAGE_LOADER, 1 },
420 
421    .getBuffers          = loader_dri3_get_buffers,
422    .flushFrontBuffer    = dri3_flush_front_buffer,
423 };
424 
425 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)426 dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
427                               const EGLint *rects, EGLint n_rects)
428 {
429    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
430 
431    return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
432                                        0, 0, 0, 0,
433                                        rects, n_rects,
434                                        draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
435 }
436 
437 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)438 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
439 {
440    return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
441 }
442 
443 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)444 dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
445 {
446    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
447    xcb_pixmap_t target;
448 
449    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
450    target = (uintptr_t) native_pixmap_target;
451 
452    loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
453                              dri3_surf->loader_drawable.drawable);
454 
455    return EGL_TRUE;
456 }
457 
458 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)459 dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
460 {
461    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
462 
463    return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
464 }
465 
466 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)467 dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
468                    EGLint attribute, EGLint *value)
469 {
470    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
471 
472    switch (attribute) {
473    case EGL_WIDTH:
474    case EGL_HEIGHT:
475       loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
476       break;
477    default:
478       break;
479    }
480 
481    return _eglQuerySurface(disp, surf, attribute, value);
482 }
483 
484 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)485 dri3_get_dri_drawable(_EGLSurface *surf)
486 {
487    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
488 
489    return dri3_surf->loader_drawable.dri_drawable;
490 }
491 
492 static void
dri3_close_screen_notify(_EGLDisplay * disp)493 dri3_close_screen_notify(_EGLDisplay *disp)
494 {
495    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
496 
497    loader_dri3_close_screen(dri2_dpy->dri_screen);
498 }
499 
500 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
501    .authenticate = dri3_authenticate,
502    .create_window_surface = dri3_create_window_surface,
503    .create_pixmap_surface = dri3_create_pixmap_surface,
504    .create_pbuffer_surface = dri3_create_pbuffer_surface,
505    .destroy_surface = dri3_destroy_surface,
506    .create_image = dri3_create_image_khr,
507    .swap_interval = dri3_set_swap_interval,
508    .swap_buffers = dri3_swap_buffers,
509    .swap_buffers_with_damage = dri3_swap_buffers_with_damage,
510    .copy_buffers = dri3_copy_buffers,
511    .query_buffer_age = dri3_query_buffer_age,
512    .query_surface = dri3_query_surface,
513    .get_sync_values = dri3_get_sync_values,
514    .get_dri_drawable = dri3_get_dri_drawable,
515    .close_screen_notify = dri3_close_screen_notify,
516 };
517 
518 /* Only request versions of these protocols which we actually support. */
519 #define DRI3_SUPPORTED_MAJOR 1
520 #define PRESENT_SUPPORTED_MAJOR 1
521 
522 #ifdef HAVE_DRI3_MODIFIERS
523 #define DRI3_SUPPORTED_MINOR 2
524 #define PRESENT_SUPPORTED_MINOR 2
525 #else
526 #define PRESENT_SUPPORTED_MINOR 0
527 #define DRI3_SUPPORTED_MINOR 0
528 #endif
529 
530 EGLBoolean
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)531 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
532 {
533    xcb_dri3_query_version_reply_t *dri3_query;
534    xcb_dri3_query_version_cookie_t dri3_query_cookie;
535    xcb_present_query_version_reply_t *present_query;
536    xcb_present_query_version_cookie_t present_query_cookie;
537    xcb_xfixes_query_version_reply_t *xfixes_query;
538    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
539    xcb_generic_error_t *error;
540    const xcb_query_extension_reply_t *extension;
541 
542    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
543    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
544    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
545 
546    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
547    if (!(extension && extension->present))
548       return EGL_FALSE;
549 
550    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
551    if (!(extension && extension->present))
552       return EGL_FALSE;
553 
554    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
555    if (!(extension && extension->present))
556       return EGL_FALSE;
557 
558    dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
559                                               DRI3_SUPPORTED_MAJOR,
560                                               DRI3_SUPPORTED_MINOR);
561 
562    present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
563                                                     PRESENT_SUPPORTED_MAJOR,
564                                                     PRESENT_SUPPORTED_MINOR);
565 
566    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
567                                                   XCB_XFIXES_MAJOR_VERSION,
568                                                   XCB_XFIXES_MINOR_VERSION);
569 
570    dri3_query =
571       xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
572    if (dri3_query == NULL || error != NULL) {
573       _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
574       free(dri3_query);
575       free(error);
576       return EGL_FALSE;
577    }
578 
579    dri2_dpy->dri3_major_version = dri3_query->major_version;
580    dri2_dpy->dri3_minor_version = dri3_query->minor_version;
581    free(dri3_query);
582 
583    present_query =
584       xcb_present_query_version_reply(dri2_dpy->conn,
585                                       present_query_cookie, &error);
586    if (present_query == NULL || error != NULL) {
587       _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
588       free(present_query);
589       free(error);
590       return EGL_FALSE;
591    }
592 
593    dri2_dpy->present_major_version = present_query->major_version;
594    dri2_dpy->present_minor_version = present_query->minor_version;
595    free(present_query);
596 
597    xfixes_query =
598       xcb_xfixes_query_version_reply(dri2_dpy->conn,
599                                       xfixes_query_cookie, &error);
600    if (xfixes_query == NULL || error != NULL ||
601        xfixes_query->major_version < 2) {
602       _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
603       free(error);
604       free(xfixes_query);
605       return EGL_FALSE;
606    }
607    free(xfixes_query);
608 
609    dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
610    if (dri2_dpy->fd < 0) {
611       int conn_error = xcb_connection_has_error(dri2_dpy->conn);
612       _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
613 
614       if (conn_error)
615          _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
616 
617       return EGL_FALSE;
618    }
619 
620    dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
621 
622    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
623    if (!dri2_dpy->driver_name) {
624       _eglLog(_EGL_WARNING, "DRI3: No driver found");
625       close(dri2_dpy->fd);
626       return EGL_FALSE;
627    }
628 
629 #ifdef HAVE_WAYLAND_PLATFORM
630    /* Only try to get a render device name since dri3 doesn't provide a
631     * mechanism for authenticating client opened device node fds. If this
632     * fails then don't advertise the extension. */
633    dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
634 #endif
635 
636    return EGL_TRUE;
637 }
638