• 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 #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 enum loader_dri3_drawable_type
egl_to_loader_dri3_drawable_type(EGLint type)137 egl_to_loader_dri3_drawable_type(EGLint type)
138 {
139    switch (type) {
140    case EGL_WINDOW_BIT:
141       return LOADER_DRI3_DRAWABLE_WINDOW;
142    case EGL_PIXMAP_BIT:
143       return LOADER_DRI3_DRAWABLE_PIXMAP;
144    case EGL_PBUFFER_BIT:
145       return LOADER_DRI3_DRAWABLE_PBUFFER;
146    default:
147       return LOADER_DRI3_DRAWABLE_UNKNOWN;
148    }
149 }
150 
151 static _EGLSurface *
dri3_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)152 dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
153                     void *native_surface, const EGLint *attrib_list)
154 {
155    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
156    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
157    struct dri3_egl_surface *dri3_surf;
158    const __DRIconfig *dri_config;
159    xcb_drawable_t drawable;
160 
161    dri3_surf = calloc(1, sizeof *dri3_surf);
162    if (!dri3_surf) {
163       _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
164       return NULL;
165    }
166 
167    if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
168                           attrib_list, false, native_surface))
169       goto cleanup_surf;
170 
171    if (type == EGL_PBUFFER_BIT) {
172       drawable = xcb_generate_id(dri2_dpy->conn);
173       xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
174                         drawable, dri2_dpy->screen->root,
175                         dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
176    } else {
177       STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
178       drawable = (uintptr_t) native_surface;
179    }
180 
181    dri_config = dri2_get_dri_config(dri2_conf, type,
182                                     dri3_surf->surf.base.GLColorspace);
183 
184    if (!dri_config) {
185       _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
186       goto cleanup_pixmap;
187    }
188 
189    if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
190                                  egl_to_loader_dri3_drawable_type(type),
191                                  dri2_dpy->dri_screen,
192                                  dri2_dpy->is_different_gpu,
193                                  dri2_dpy->multibuffers_available,
194                                  true,
195                                  dri_config,
196                                  &dri2_dpy->loader_dri3_ext,
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->is_different_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->device_name) {
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,
253                               native_window, 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,
265                               native_pixmap, 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,
273                               NULL, attrib_list);
274 }
275 
276 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)277 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
278                      EGLuint64KHR *ust, EGLuint64KHR *msc,
279                      EGLuint64KHR *sbc)
280 {
281    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
282 
283    return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
284                                    (int64_t *) ust, (int64_t *) msc,
285                                    (int64_t *) sbc) ? EGL_TRUE : 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 format;
298 
299    drawable = (xcb_drawable_t) (uintptr_t) buffer;
300    bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
301    bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
302                                                 bp_cookie, NULL);
303    if (!bp_reply) {
304       _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
305       return NULL;
306    }
307 
308    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
309    if (format == __DRI_IMAGE_FORMAT_NONE) {
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(dri2_dpy->conn,
326                                                   bp_reply,
327                                                   format,
328                                                   dri2_dpy->dri_screen,
329                                                   dri2_dpy->image,
330                                                   dri2_img);
331 
332    free(bp_reply);
333 
334    return &dri2_img->base;
335 }
336 
337 #ifdef HAVE_DRI3_MODIFIERS
338 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)339 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
340                                           EGLClientBuffer buffer,
341                                           const EGLint *attr_list)
342 {
343    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
344    struct dri2_egl_image *dri2_img;
345    xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
346    xcb_dri3_buffers_from_pixmap_reply_t  *bp_reply;
347    xcb_drawable_t drawable;
348    unsigned int format;
349 
350    drawable = (xcb_drawable_t) (uintptr_t) buffer;
351    bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
352    bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
353                                                  bp_cookie, NULL);
354 
355    if (!bp_reply) {
356       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
357       return EGL_NO_IMAGE_KHR;
358    }
359 
360    format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
361    if (format == __DRI_IMAGE_FORMAT_NONE) {
362       _eglError(EGL_BAD_PARAMETER,
363                 "dri3_create_image_khr: unsupported pixmap depth");
364       free(bp_reply);
365       return EGL_NO_IMAGE_KHR;
366    }
367 
368    dri2_img = malloc(sizeof *dri2_img);
369    if (!dri2_img) {
370       _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
371       free(bp_reply);
372       return EGL_NO_IMAGE_KHR;
373    }
374 
375    _eglInitImage(&dri2_img->base, disp);
376 
377    dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
378                                                                bp_reply,
379                                                                format,
380                                                                dri2_dpy->dri_screen,
381                                                                dri2_dpy->image,
382                                                                dri2_img);
383    free(bp_reply);
384 
385    if (!dri2_img->dri_image) {
386       _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
387       free(dri2_img);
388       return EGL_NO_IMAGE_KHR;
389    }
390 
391    return &dri2_img->base;
392 }
393 #endif
394 
395 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)396 dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
397                       EGLClientBuffer buffer, const EGLint *attr_list)
398 {
399 #ifdef HAVE_DRI3_MODIFIERS
400    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
401 #endif
402 
403    switch (target) {
404    case EGL_NATIVE_PIXMAP_KHR:
405 #ifdef HAVE_DRI3_MODIFIERS
406       if (dri2_dpy->multibuffers_available)
407          return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
408                                                           attr_list);
409 #endif
410       return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
411    default:
412       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
413    }
414 }
415 
416 /**
417  * Called by the driver when it needs to update the real front buffer with the
418  * contents of its fake front buffer.
419  */
420 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)421 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
422 {
423    struct loader_dri3_drawable *draw = loaderPrivate;
424    (void) driDrawable;
425 
426    /* There does not seem to be any kind of consensus on whether we should
427     * support front-buffer rendering or not:
428     * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
429     */
430    if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW)
431       _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
432 }
433 
434 const __DRIimageLoaderExtension dri3_image_loader_extension = {
435    .base = { __DRI_IMAGE_LOADER, 1 },
436 
437    .getBuffers          = loader_dri3_get_buffers,
438    .flushFrontBuffer    = dri3_flush_front_buffer,
439 };
440 
441 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)442 dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
443                               const EGLint *rects, EGLint n_rects)
444 {
445    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
446 
447    return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
448                                        0, 0, 0, 0,
449                                        rects, n_rects,
450                                        draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
451 }
452 
453 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)454 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
455 {
456    return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
457 }
458 
459 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)460 dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
461 {
462    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
463    xcb_pixmap_t target;
464 
465    STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
466    target = (uintptr_t) native_pixmap_target;
467 
468    loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
469                              dri3_surf->loader_drawable.drawable);
470 
471    return EGL_TRUE;
472 }
473 
474 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)475 dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
476 {
477    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
478 
479    return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
480 }
481 
482 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)483 dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
484                    EGLint attribute, EGLint *value)
485 {
486    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
487 
488    switch (attribute) {
489    case EGL_WIDTH:
490    case EGL_HEIGHT:
491       loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
492       break;
493    default:
494       break;
495    }
496 
497    return _eglQuerySurface(disp, surf, attribute, value);
498 }
499 
500 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)501 dri3_get_dri_drawable(_EGLSurface *surf)
502 {
503    struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
504 
505    return dri3_surf->loader_drawable.dri_drawable;
506 }
507 
508 static void
dri3_close_screen_notify(_EGLDisplay * disp)509 dri3_close_screen_notify(_EGLDisplay *disp)
510 {
511    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
512 
513    loader_dri3_close_screen(dri2_dpy->dri_screen);
514 }
515 
516 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
517    .authenticate = dri3_authenticate,
518    .create_window_surface = dri3_create_window_surface,
519    .create_pixmap_surface = dri3_create_pixmap_surface,
520    .create_pbuffer_surface = dri3_create_pbuffer_surface,
521    .destroy_surface = dri3_destroy_surface,
522    .create_image = dri3_create_image_khr,
523    .swap_interval = dri3_set_swap_interval,
524    .swap_buffers = dri3_swap_buffers,
525    .swap_buffers_with_damage = dri3_swap_buffers_with_damage,
526    .copy_buffers = dri3_copy_buffers,
527    .query_buffer_age = dri3_query_buffer_age,
528    .query_surface = dri3_query_surface,
529    .get_sync_values = dri3_get_sync_values,
530    .get_dri_drawable = dri3_get_dri_drawable,
531    .close_screen_notify = dri3_close_screen_notify,
532 };
533 
534 /* Only request versions of these protocols which we actually support. */
535 #define DRI3_SUPPORTED_MAJOR 1
536 #define PRESENT_SUPPORTED_MAJOR 1
537 
538 #ifdef HAVE_DRI3_MODIFIERS
539 #define DRI3_SUPPORTED_MINOR 2
540 #define PRESENT_SUPPORTED_MINOR 2
541 #else
542 #define PRESENT_SUPPORTED_MINOR 0
543 #define DRI3_SUPPORTED_MINOR 0
544 #endif
545 
546 EGLBoolean
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)547 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
548 {
549    xcb_dri3_query_version_reply_t *dri3_query;
550    xcb_dri3_query_version_cookie_t dri3_query_cookie;
551    xcb_present_query_version_reply_t *present_query;
552    xcb_present_query_version_cookie_t present_query_cookie;
553    xcb_xfixes_query_version_reply_t *xfixes_query;
554    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
555    xcb_generic_error_t *error;
556    const xcb_query_extension_reply_t *extension;
557 
558    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
559    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
560    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
561 
562    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
563    if (!(extension && extension->present))
564       return EGL_FALSE;
565 
566    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
567    if (!(extension && extension->present))
568       return EGL_FALSE;
569 
570    extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
571    if (!(extension && extension->present))
572       return EGL_FALSE;
573 
574    dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
575                                               DRI3_SUPPORTED_MAJOR,
576                                               DRI3_SUPPORTED_MINOR);
577 
578    present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
579                                                     PRESENT_SUPPORTED_MAJOR,
580                                                     PRESENT_SUPPORTED_MINOR);
581 
582    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
583                                                   XCB_XFIXES_MAJOR_VERSION,
584                                                   XCB_XFIXES_MINOR_VERSION);
585 
586    dri3_query =
587       xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
588    if (dri3_query == NULL || error != NULL) {
589       _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
590       free(dri3_query);
591       free(error);
592       return EGL_FALSE;
593    }
594 
595    dri2_dpy->dri3_major_version = dri3_query->major_version;
596    dri2_dpy->dri3_minor_version = dri3_query->minor_version;
597    free(dri3_query);
598 
599    present_query =
600       xcb_present_query_version_reply(dri2_dpy->conn,
601                                       present_query_cookie, &error);
602    if (present_query == NULL || error != NULL) {
603       _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
604       free(present_query);
605       free(error);
606       return EGL_FALSE;
607    }
608 
609    dri2_dpy->present_major_version = present_query->major_version;
610    dri2_dpy->present_minor_version = present_query->minor_version;
611    free(present_query);
612 
613    xfixes_query =
614       xcb_xfixes_query_version_reply(dri2_dpy->conn,
615                                       xfixes_query_cookie, &error);
616    if (xfixes_query == NULL || error != NULL ||
617        xfixes_query->major_version < 2) {
618       _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
619       free(error);
620       free(xfixes_query);
621       return EGL_FALSE;
622    }
623    free(xfixes_query);
624 
625    dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
626    if (dri2_dpy->fd < 0) {
627       int conn_error = xcb_connection_has_error(dri2_dpy->conn);
628       _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
629 
630       if (conn_error)
631          _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
632 
633       return EGL_FALSE;
634    }
635 
636    dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
637 
638    dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
639    if (!dri2_dpy->driver_name) {
640       _eglLog(_EGL_WARNING, "DRI3: No driver found");
641       close(dri2_dpy->fd);
642       return EGL_FALSE;
643    }
644 
645 #ifdef HAVE_WAYLAND_PLATFORM
646    /* Only try to get a render device name since dri3 doesn't provide a
647     * mechanism for authenticating client opened device node fds. If this
648     * fails then don't advertise the extension. */
649    dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
650 #endif
651 
652    return EGL_TRUE;
653 }
654