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