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