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                                  dri_config,
179                                  &dri2_dpy->loader_dri3_ext,
180                                  &egl_dri3_vtable,
181                                  &dri3_surf->loader_drawable)) {
182       _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
183       goto cleanup_pixmap;
184    }
185 
186    if (dri3_surf->surf.base.ProtectedContent &&
187        dri2_dpy->is_different_gpu) {
188       _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
189       goto cleanup_pixmap;
190    }
191 
192    dri3_surf->loader_drawable.is_protected_content =
193       dri3_surf->surf.base.ProtectedContent;
194 
195    return &dri3_surf->surf.base;
196 
197  cleanup_pixmap:
198    if (type == EGL_PBUFFER_BIT)
199       xcb_free_pixmap(dri2_dpy->conn, drawable);
200  cleanup_surf:
201    free(dri3_surf);
202 
203    return NULL;
204 }
205 
206 static int
dri3_authenticate(_EGLDisplay * disp,uint32_t id)207 dri3_authenticate(_EGLDisplay *disp, uint32_t id)
208 {
209 #ifdef HAVE_WAYLAND_PLATFORM
210    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
211 
212    if (dri2_dpy->device_name) {
213       _eglLog(_EGL_WARNING,
214               "Wayland client render node authentication is unnecessary");
215       return 0;
216    }
217 
218    _eglLog(_EGL_WARNING,
219            "Wayland client primary node authentication isn't supported");
220 #endif
221 
222    return -1;
223 }
224 
225 /**
226  * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
227  */
228 static _EGLSurface *
dri3_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)229 dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
230                            void *native_window, const EGLint *attrib_list)
231 {
232    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
233    _EGLSurface *surf;
234 
235    surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
236                               native_window, attrib_list);
237    if (surf != NULL)
238       dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
239 
240    return surf;
241 }
242 
243 static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)244 dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
245                            void *native_pixmap, const EGLint *attrib_list)
246 {
247    return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf,
248                               native_pixmap, attrib_list);
249 }
250 
251 static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)252 dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
253                             const EGLint *attrib_list)
254 {
255    return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
256                               NULL, attrib_list);
257 }
258 
259 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)260 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
261                      EGLuint64KHR *ust, EGLuint64KHR *msc,
262                      EGLuint64KHR *sbc)
263 {
264    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
265 
266    return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
267                                    (int64_t *) ust, (int64_t *) msc,
268                                    (int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
269 }
270 
271 static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)272 dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
273                              EGLClientBuffer buffer, const EGLint *attr_list)
274 {
275    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
276    struct dri2_egl_image *dri2_img;
277    xcb_drawable_t drawable;
278    xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
279    xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
280    unsigned int format;
281 
282    drawable = (xcb_drawable_t) (uintptr_t) buffer;
283    bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
284    bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
285                                                 bp_cookie, NULL);
286    if (!bp_reply) {
287       _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
288       return NULL;
289    }
290 
291    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
292    if (format == __DRI_IMAGE_FORMAT_NONE) {
293       _eglError(EGL_BAD_PARAMETER,
294                 "dri3_create_image_khr: unsupported pixmap depth");
295       free(bp_reply);
296       return EGL_NO_IMAGE_KHR;
297    }
298 
299    dri2_img = malloc(sizeof *dri2_img);
300    if (!dri2_img) {
301       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
302       free(bp_reply);
303       return EGL_NO_IMAGE_KHR;
304    }
305 
306    _eglInitImage(&dri2_img->base, disp);
307 
308    dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
309                                                   bp_reply,
310                                                   format,
311                                                   dri2_dpy->dri_screen,
312                                                   dri2_dpy->image,
313                                                   dri2_img);
314 
315    free(bp_reply);
316 
317    return &dri2_img->base;
318 }
319 
320 #ifdef HAVE_DRI3_MODIFIERS
321 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)322 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
323                                           EGLClientBuffer buffer,
324                                           const EGLint *attr_list)
325 {
326    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
327    struct dri2_egl_image *dri2_img;
328    xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
329    xcb_dri3_buffers_from_pixmap_reply_t  *bp_reply;
330    xcb_drawable_t drawable;
331    unsigned int format;
332 
333    drawable = (xcb_drawable_t) (uintptr_t) buffer;
334    bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
335    bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
336                                                  bp_cookie, NULL);
337 
338    if (!bp_reply) {
339       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
340       return EGL_NO_IMAGE_KHR;
341    }
342 
343    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
344    if (format == __DRI_IMAGE_FORMAT_NONE) {
345       _eglError(EGL_BAD_PARAMETER,
346                 "dri3_create_image_khr: unsupported pixmap depth");
347       free(bp_reply);
348       return EGL_NO_IMAGE_KHR;
349    }
350 
351    dri2_img = malloc(sizeof *dri2_img);
352    if (!dri2_img) {
353       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
354       free(bp_reply);
355       return EGL_NO_IMAGE_KHR;
356    }
357 
358    _eglInitImage(&dri2_img->base, disp);
359 
360    dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
361                                                                bp_reply,
362                                                                format,
363                                                                dri2_dpy->dri_screen,
364                                                                dri2_dpy->image,
365                                                                dri2_img);
366    free(bp_reply);
367 
368    if (!dri2_img->dri_image) {
369       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
370       free(dri2_img);
371       return EGL_NO_IMAGE_KHR;
372    }
373 
374    return &dri2_img->base;
375 }
376 #endif
377 
378 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)379 dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
380                       EGLClientBuffer buffer, const EGLint *attr_list)
381 {
382 #ifdef HAVE_DRI3_MODIFIERS
383    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
384 #endif
385 
386    switch (target) {
387    case EGL_NATIVE_PIXMAP_KHR:
388 #ifdef HAVE_DRI3_MODIFIERS
389       if (dri2_dpy->multibuffers_available)
390          return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
391                                                           attr_list);
392 #endif
393       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
394    default:
395       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
396    }
397 }
398 
399 /**
400  * Called by the driver when it needs to update the real front buffer with the
401  * contents of its fake front buffer.
402  */
403 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)404 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
405 {
406    struct loader_dri3_drawable *draw = loaderPrivate;
407    (void) driDrawable;
408 
409    /* There does not seem to be any kind of consensus on whether we should
410     * support front-buffer rendering or not:
411     * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
412     */
413    if (!draw->is_pixmap)
414       _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
415 }
416 
417 const __DRIimageLoaderExtension dri3_image_loader_extension = {
418    .base = { __DRI_IMAGE_LOADER, 1 },
419 
420    .getBuffers          = loader_dri3_get_buffers,
421    .flushFrontBuffer    = dri3_flush_front_buffer,
422 };
423 
424 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)425 dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
426                               const EGLint *rects, EGLint n_rects)
427 {
428    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
429 
430    return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
431                                        0, 0, 0, 0,
432                                        rects, n_rects,
433                                        draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
434 }
435 
436 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)437 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
438 {
439    return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
440 }
441 
442 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)443 dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
444 {
445    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
446    xcb_pixmap_t target;
447 
448    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
449    target = (uintptr_t) native_pixmap_target;
450 
451    loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
452                              dri3_surf->loader_drawable.drawable);
453 
454    return EGL_TRUE;
455 }
456 
457 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)458 dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
459 {
460    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
461 
462    return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
463 }
464 
465 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)466 dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
467                    EGLint attribute, EGLint *value)
468 {
469    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
470 
471    switch (attribute) {
472    case EGL_WIDTH:
473    case EGL_HEIGHT:
474       loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
475       break;
476    default:
477       break;
478    }
479 
480    return _eglQuerySurface(disp, surf, attribute, value);
481 }
482 
483 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)484 dri3_get_dri_drawable(_EGLSurface *surf)
485 {
486    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
487 
488    return dri3_surf->loader_drawable.dri_drawable;
489 }
490 
491 static void
dri3_close_screen_notify(_EGLDisplay * disp)492 dri3_close_screen_notify(_EGLDisplay *disp)
493 {
494    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
495 
496    loader_dri3_close_screen(dri2_dpy->dri_screen);
497 }
498 
499 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
500    .authenticate = dri3_authenticate,
501    .create_window_surface = dri3_create_window_surface,
502    .create_pixmap_surface = dri3_create_pixmap_surface,
503    .create_pbuffer_surface = dri3_create_pbuffer_surface,
504    .destroy_surface = dri3_destroy_surface,
505    .create_image = dri3_create_image_khr,
506    .swap_interval = dri3_set_swap_interval,
507    .swap_buffers = dri3_swap_buffers,
508    .swap_buffers_with_damage = dri3_swap_buffers_with_damage,
509    .copy_buffers = dri3_copy_buffers,
510    .query_buffer_age = dri3_query_buffer_age,
511    .query_surface = dri3_query_surface,
512    .get_sync_values = dri3_get_sync_values,
513    .get_dri_drawable = dri3_get_dri_drawable,
514    .close_screen_notify = dri3_close_screen_notify,
515 };
516 
517 /* Only request versions of these protocols which we actually support. */
518 #define DRI3_SUPPORTED_MAJOR 1
519 #define PRESENT_SUPPORTED_MAJOR 1
520 
521 #ifdef HAVE_DRI3_MODIFIERS
522 #define DRI3_SUPPORTED_MINOR 2
523 #define PRESENT_SUPPORTED_MINOR 2
524 #else
525 #define PRESENT_SUPPORTED_MINOR 0
526 #define DRI3_SUPPORTED_MINOR 0
527 #endif
528 
529 EGLBoolean
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)530 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
531 {
532    xcb_dri3_query_version_reply_t *dri3_query;
533    xcb_dri3_query_version_cookie_t dri3_query_cookie;
534    xcb_present_query_version_reply_t *present_query;
535    xcb_present_query_version_cookie_t present_query_cookie;
536    xcb_xfixes_query_version_reply_t *xfixes_query;
537    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
538    xcb_generic_error_t *error;
539    const xcb_query_extension_reply_t *extension;
540 
541    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
542    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
543    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
544 
545    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
546    if (!(extension && extension->present))
547       return EGL_FALSE;
548 
549    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
550    if (!(extension && extension->present))
551       return EGL_FALSE;
552 
553    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
554    if (!(extension && extension->present))
555       return EGL_FALSE;
556 
557    dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
558                                               DRI3_SUPPORTED_MAJOR,
559                                               DRI3_SUPPORTED_MINOR);
560 
561    present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
562                                                     PRESENT_SUPPORTED_MAJOR,
563                                                     PRESENT_SUPPORTED_MINOR);
564 
565    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
566                                                   XCB_XFIXES_MAJOR_VERSION,
567                                                   XCB_XFIXES_MINOR_VERSION);
568 
569    dri3_query =
570       xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
571    if (dri3_query == NULL || error != NULL) {
572       _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
573       free(dri3_query);
574       free(error);
575       return EGL_FALSE;
576    }
577 
578    dri2_dpy->dri3_major_version = dri3_query->major_version;
579    dri2_dpy->dri3_minor_version = dri3_query->minor_version;
580    free(dri3_query);
581 
582    present_query =
583       xcb_present_query_version_reply(dri2_dpy->conn,
584                                       present_query_cookie, &error);
585    if (present_query == NULL || error != NULL) {
586       _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
587       free(present_query);
588       free(error);
589       return EGL_FALSE;
590    }
591 
592    dri2_dpy->present_major_version = present_query->major_version;
593    dri2_dpy->present_minor_version = present_query->minor_version;
594    free(present_query);
595 
596    xfixes_query =
597       xcb_xfixes_query_version_reply(dri2_dpy->conn,
598                                       xfixes_query_cookie, &error);
599    if (xfixes_query == NULL || error != NULL ||
600        xfixes_query->major_version < 2) {
601       _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
602       free(error);
603       free(xfixes_query);
604       return EGL_FALSE;
605    }
606    free(xfixes_query);
607 
608    dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
609    if (dri2_dpy->fd < 0) {
610       int conn_error = xcb_connection_has_error(dri2_dpy->conn);
611       _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
612 
613       if (conn_error)
614          _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
615 
616       return EGL_FALSE;
617    }
618 
619    dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
620 
621    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
622    if (!dri2_dpy->driver_name) {
623       _eglLog(_EGL_WARNING, "DRI3: No driver found");
624       close(dri2_dpy->fd);
625       return EGL_FALSE;
626    }
627 
628 #ifdef HAVE_WAYLAND_PLATFORM
629    /* Only try to get a render device name since dri3 doesn't provide a
630     * mechanism for authenticating client opened device node fds. If this
631     * fails then don't advertise the extension. */
632    dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
633 #endif
634 
635    return EGL_TRUE;
636 }
637