1 /*
2 * Copyright © 2015 Boyan Ding
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <xcb/xcb.h>
29 #include <xcb/dri3.h>
30 #include <xcb/present.h>
31 #include <xcb/xfixes.h>
32
33 #include <xf86drm.h>
34 #include "util/macros.h"
35
36 #include "egl_dri2.h"
37 #include "platform_x11_dri3.h"
38
39 #include "loader.h"
40 #include "loader_dri3_helper.h"
41
42 static struct dri3_egl_surface *
loader_drawable_to_egl_surface(struct loader_dri3_drawable * draw)43 loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {
44 size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
45 return (struct dri3_egl_surface *)(((void*) draw) - offset);
46 }
47
48 static void
egl_dri3_set_drawable_size(struct loader_dri3_drawable * draw,int width,int height)49 egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
50 int width, int height)
51 {
52 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
53
54 dri3_surf->surf.base.Width = width;
55 dri3_surf->surf.base.Height = height;
56 }
57
58 static bool
egl_dri3_in_current_context(struct loader_dri3_drawable * draw)59 egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
60 {
61 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
62 _EGLContext *ctx = _eglGetCurrentContext();
63
64 return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
65 }
66
67 static __DRIcontext *
egl_dri3_get_dri_context(struct loader_dri3_drawable * draw)68 egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
69 {
70 _EGLContext *ctx = _eglGetCurrentContext();
71 struct dri2_egl_context *dri2_ctx;
72 if (!ctx)
73 return NULL;
74 dri2_ctx = dri2_egl_context(ctx);
75 return dri2_ctx->dri_context;
76 }
77
78 static __DRIscreen *
egl_dri3_get_dri_screen(void)79 egl_dri3_get_dri_screen(void)
80 {
81 _EGLContext *ctx = _eglGetCurrentContext();
82 struct dri2_egl_context *dri2_ctx;
83 if (!ctx)
84 return NULL;
85 dri2_ctx = dri2_egl_context(ctx);
86 return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;
87 }
88
89 static void
egl_dri3_flush_drawable(struct loader_dri3_drawable * draw,unsigned flags)90 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
91 {
92 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
93 _EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
94
95 dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
96 }
97
98 static const struct loader_dri3_vtable egl_dri3_vtable = {
99 .set_drawable_size = egl_dri3_set_drawable_size,
100 .in_current_context = egl_dri3_in_current_context,
101 .get_dri_context = egl_dri3_get_dri_context,
102 .get_dri_screen = egl_dri3_get_dri_screen,
103 .flush_drawable = egl_dri3_flush_drawable,
104 .show_fps = NULL,
105 };
106
107 static EGLBoolean
dri3_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)108 dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
109 {
110 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
111 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
112 xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
113
114 loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
115
116 if (surf->Type == EGL_PBUFFER_BIT)
117 xcb_free_pixmap (dri2_dpy->conn, drawable);
118
119 dri2_fini_surface(surf);
120 free(surf);
121
122 return EGL_TRUE;
123 }
124
125 static EGLBoolean
dri3_set_swap_interval(_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)126 dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
127 {
128 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
129
130 dri3_surf->surf.base.SwapInterval = interval;
131 loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
132
133 return EGL_TRUE;
134 }
135
136 static _EGLSurface *
dri3_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)137 dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
138 void *native_surface, const EGLint *attrib_list)
139 {
140 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
141 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
142 struct dri3_egl_surface *dri3_surf;
143 const __DRIconfig *dri_config;
144 xcb_drawable_t drawable;
145
146 dri3_surf = calloc(1, sizeof *dri3_surf);
147 if (!dri3_surf) {
148 _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
149 return NULL;
150 }
151
152 if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,
153 attrib_list, false, native_surface))
154 goto cleanup_surf;
155
156 if (type == EGL_PBUFFER_BIT) {
157 drawable = xcb_generate_id(dri2_dpy->conn);
158 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,
159 drawable, dri2_dpy->screen->root,
160 dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);
161 } else {
162 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
163 drawable = (uintptr_t) native_surface;
164 }
165
166 dri_config = dri2_get_dri_config(dri2_conf, type,
167 dri3_surf->surf.base.GLColorspace);
168
169 if (!dri_config) {
170 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
171 goto cleanup_pixmap;
172 }
173
174 if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,
175 dri2_dpy->dri_screen,
176 dri2_dpy->is_different_gpu,
177 dri2_dpy->multibuffers_available,
178 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
207 static int
dri3_authenticate(_EGLDisplay * disp,uint32_t id)208 dri3_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 */
229 static _EGLSurface *
dri3_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)230 dri3_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
244 static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)245 dri3_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
252 static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)253 dri3_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
260 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)261 dri3_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
272 static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)273 dri3_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
322 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)323 dri3_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
379 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)380 dri3_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 */
404 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)405 dri3_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
418 const __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
425 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)426 dri3_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
437 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)438 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
439 {
440 return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
441 }
442
443 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)444 dri3_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
458 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)459 dri3_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
466 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)467 dri3_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
484 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)485 dri3_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
492 static void
dri3_close_screen_notify(_EGLDisplay * disp)493 dri3_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
500 struct 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
530 EGLBoolean
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)531 dri3_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