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
42static struct dri3_egl_surface *
43loader_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
48static void
49egl_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
58static bool
59egl_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
67static __DRIcontext *
68egl_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
78static __DRIscreen *
79egl_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
89static void
90egl_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
98static 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
107static EGLBoolean
108dri3_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
125static EGLBoolean
126dri3_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
136static _EGLSurface *
137dri3_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
207static int
208dri3_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 */
229static _EGLSurface *
230dri3_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
244static _EGLSurface *
245dri3_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
252static _EGLSurface *
253dri3_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
260static EGLBoolean
261dri3_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
272static _EGLImage *
273dri3_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
322static _EGLImage *
323dri3_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
379static _EGLImage *
380dri3_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 */
404static void
405dri3_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
418const __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
425static EGLBoolean
426dri3_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
437static EGLBoolean
438dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
439{
440   return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
441}
442
443static EGLBoolean
444dri3_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
458static int
459dri3_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
466static EGLBoolean
467dri3_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
484static __DRIdrawable *
485dri3_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
492static void
493dri3_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
500struct 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
530EGLBoolean
531dri3_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