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 dri_config,
179 &dri2_dpy->loader_dri3_ext,
180 &egl_dri3_vtable,
181 &dri3_surf->loader_drawable)) {
182 _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
183 goto cleanup_pixmap;
184 }
185
186 if (dri3_surf->surf.base.ProtectedContent &&
187 dri2_dpy->is_different_gpu) {
188 _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
189 goto cleanup_pixmap;
190 }
191
192 dri3_surf->loader_drawable.is_protected_content =
193 dri3_surf->surf.base.ProtectedContent;
194
195 return &dri3_surf->surf.base;
196
197 cleanup_pixmap:
198 if (type == EGL_PBUFFER_BIT)
199 xcb_free_pixmap(dri2_dpy->conn, drawable);
200 cleanup_surf:
201 free(dri3_surf);
202
203 return NULL;
204 }
205
206 static int
dri3_authenticate(_EGLDisplay * disp,uint32_t id)207 dri3_authenticate(_EGLDisplay *disp, uint32_t id)
208 {
209 #ifdef HAVE_WAYLAND_PLATFORM
210 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
211
212 if (dri2_dpy->device_name) {
213 _eglLog(_EGL_WARNING,
214 "Wayland client render node authentication is unnecessary");
215 return 0;
216 }
217
218 _eglLog(_EGL_WARNING,
219 "Wayland client primary node authentication isn't supported");
220 #endif
221
222 return -1;
223 }
224
225 /**
226 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
227 */
228 static _EGLSurface *
dri3_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)229 dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
230 void *native_window, const EGLint *attrib_list)
231 {
232 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
233 _EGLSurface *surf;
234
235 surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,
236 native_window, attrib_list);
237 if (surf != NULL)
238 dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
239
240 return surf;
241 }
242
243 static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)244 dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
245 void *native_pixmap, const EGLint *attrib_list)
246 {
247 return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf,
248 native_pixmap, attrib_list);
249 }
250
251 static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)252 dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
253 const EGLint *attrib_list)
254 {
255 return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,
256 NULL, attrib_list);
257 }
258
259 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)260 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
261 EGLuint64KHR *ust, EGLuint64KHR *msc,
262 EGLuint64KHR *sbc)
263 {
264 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
265
266 return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
267 (int64_t *) ust, (int64_t *) msc,
268 (int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;
269 }
270
271 static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)272 dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
273 EGLClientBuffer buffer, const EGLint *attr_list)
274 {
275 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
276 struct dri2_egl_image *dri2_img;
277 xcb_drawable_t drawable;
278 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
279 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
280 unsigned int format;
281
282 drawable = (xcb_drawable_t) (uintptr_t) buffer;
283 bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
284 bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,
285 bp_cookie, NULL);
286 if (!bp_reply) {
287 _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
288 return NULL;
289 }
290
291 format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
292 if (format == __DRI_IMAGE_FORMAT_NONE) {
293 _eglError(EGL_BAD_PARAMETER,
294 "dri3_create_image_khr: unsupported pixmap depth");
295 free(bp_reply);
296 return EGL_NO_IMAGE_KHR;
297 }
298
299 dri2_img = malloc(sizeof *dri2_img);
300 if (!dri2_img) {
301 _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
302 free(bp_reply);
303 return EGL_NO_IMAGE_KHR;
304 }
305
306 _eglInitImage(&dri2_img->base, disp);
307
308 dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,
309 bp_reply,
310 format,
311 dri2_dpy->dri_screen,
312 dri2_dpy->image,
313 dri2_img);
314
315 free(bp_reply);
316
317 return &dri2_img->base;
318 }
319
320 #ifdef HAVE_DRI3_MODIFIERS
321 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)322 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
323 EGLClientBuffer buffer,
324 const EGLint *attr_list)
325 {
326 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
327 struct dri2_egl_image *dri2_img;
328 xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
329 xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
330 xcb_drawable_t drawable;
331 unsigned int format;
332
333 drawable = (xcb_drawable_t) (uintptr_t) buffer;
334 bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
335 bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,
336 bp_cookie, NULL);
337
338 if (!bp_reply) {
339 _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
340 return EGL_NO_IMAGE_KHR;
341 }
342
343 format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
344 if (format == __DRI_IMAGE_FORMAT_NONE) {
345 _eglError(EGL_BAD_PARAMETER,
346 "dri3_create_image_khr: unsupported pixmap depth");
347 free(bp_reply);
348 return EGL_NO_IMAGE_KHR;
349 }
350
351 dri2_img = malloc(sizeof *dri2_img);
352 if (!dri2_img) {
353 _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
354 free(bp_reply);
355 return EGL_NO_IMAGE_KHR;
356 }
357
358 _eglInitImage(&dri2_img->base, disp);
359
360 dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,
361 bp_reply,
362 format,
363 dri2_dpy->dri_screen,
364 dri2_dpy->image,
365 dri2_img);
366 free(bp_reply);
367
368 if (!dri2_img->dri_image) {
369 _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
370 free(dri2_img);
371 return EGL_NO_IMAGE_KHR;
372 }
373
374 return &dri2_img->base;
375 }
376 #endif
377
378 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)379 dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
380 EGLClientBuffer buffer, const EGLint *attr_list)
381 {
382 #ifdef HAVE_DRI3_MODIFIERS
383 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
384 #endif
385
386 switch (target) {
387 case EGL_NATIVE_PIXMAP_KHR:
388 #ifdef HAVE_DRI3_MODIFIERS
389 if (dri2_dpy->multibuffers_available)
390 return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
391 attr_list);
392 #endif
393 return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
394 default:
395 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
396 }
397 }
398
399 /**
400 * Called by the driver when it needs to update the real front buffer with the
401 * contents of its fake front buffer.
402 */
403 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)404 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
405 {
406 struct loader_dri3_drawable *draw = loaderPrivate;
407 (void) driDrawable;
408
409 /* There does not seem to be any kind of consensus on whether we should
410 * support front-buffer rendering or not:
411 * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
412 */
413 if (!draw->is_pixmap)
414 _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
415 }
416
417 const __DRIimageLoaderExtension dri3_image_loader_extension = {
418 .base = { __DRI_IMAGE_LOADER, 1 },
419
420 .getBuffers = loader_dri3_get_buffers,
421 .flushFrontBuffer = dri3_flush_front_buffer,
422 };
423
424 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)425 dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
426 const EGLint *rects, EGLint n_rects)
427 {
428 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
429
430 return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,
431 0, 0, 0, 0,
432 rects, n_rects,
433 draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
434 }
435
436 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)437 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
438 {
439 return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
440 }
441
442 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)443 dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)
444 {
445 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
446 xcb_pixmap_t target;
447
448 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
449 target = (uintptr_t) native_pixmap_target;
450
451 loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
452 dri3_surf->loader_drawable.drawable);
453
454 return EGL_TRUE;
455 }
456
457 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)458 dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
459 {
460 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
461
462 return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
463 }
464
465 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)466 dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
467 EGLint attribute, EGLint *value)
468 {
469 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
470
471 switch (attribute) {
472 case EGL_WIDTH:
473 case EGL_HEIGHT:
474 loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
475 break;
476 default:
477 break;
478 }
479
480 return _eglQuerySurface(disp, surf, attribute, value);
481 }
482
483 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)484 dri3_get_dri_drawable(_EGLSurface *surf)
485 {
486 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
487
488 return dri3_surf->loader_drawable.dri_drawable;
489 }
490
491 static void
dri3_close_screen_notify(_EGLDisplay * disp)492 dri3_close_screen_notify(_EGLDisplay *disp)
493 {
494 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
495
496 loader_dri3_close_screen(dri2_dpy->dri_screen);
497 }
498
499 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
500 .authenticate = dri3_authenticate,
501 .create_window_surface = dri3_create_window_surface,
502 .create_pixmap_surface = dri3_create_pixmap_surface,
503 .create_pbuffer_surface = dri3_create_pbuffer_surface,
504 .destroy_surface = dri3_destroy_surface,
505 .create_image = dri3_create_image_khr,
506 .swap_interval = dri3_set_swap_interval,
507 .swap_buffers = dri3_swap_buffers,
508 .swap_buffers_with_damage = dri3_swap_buffers_with_damage,
509 .copy_buffers = dri3_copy_buffers,
510 .query_buffer_age = dri3_query_buffer_age,
511 .query_surface = dri3_query_surface,
512 .get_sync_values = dri3_get_sync_values,
513 .get_dri_drawable = dri3_get_dri_drawable,
514 .close_screen_notify = dri3_close_screen_notify,
515 };
516
517 /* Only request versions of these protocols which we actually support. */
518 #define DRI3_SUPPORTED_MAJOR 1
519 #define PRESENT_SUPPORTED_MAJOR 1
520
521 #ifdef HAVE_DRI3_MODIFIERS
522 #define DRI3_SUPPORTED_MINOR 2
523 #define PRESENT_SUPPORTED_MINOR 2
524 #else
525 #define PRESENT_SUPPORTED_MINOR 0
526 #define DRI3_SUPPORTED_MINOR 0
527 #endif
528
529 EGLBoolean
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)530 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
531 {
532 xcb_dri3_query_version_reply_t *dri3_query;
533 xcb_dri3_query_version_cookie_t dri3_query_cookie;
534 xcb_present_query_version_reply_t *present_query;
535 xcb_present_query_version_cookie_t present_query_cookie;
536 xcb_xfixes_query_version_reply_t *xfixes_query;
537 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
538 xcb_generic_error_t *error;
539 const xcb_query_extension_reply_t *extension;
540
541 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
542 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
543 xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
544
545 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);
546 if (!(extension && extension->present))
547 return EGL_FALSE;
548
549 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
550 if (!(extension && extension->present))
551 return EGL_FALSE;
552
553 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
554 if (!(extension && extension->present))
555 return EGL_FALSE;
556
557 dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,
558 DRI3_SUPPORTED_MAJOR,
559 DRI3_SUPPORTED_MINOR);
560
561 present_query_cookie = xcb_present_query_version(dri2_dpy->conn,
562 PRESENT_SUPPORTED_MAJOR,
563 PRESENT_SUPPORTED_MINOR);
564
565 xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
566 XCB_XFIXES_MAJOR_VERSION,
567 XCB_XFIXES_MINOR_VERSION);
568
569 dri3_query =
570 xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
571 if (dri3_query == NULL || error != NULL) {
572 _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
573 free(dri3_query);
574 free(error);
575 return EGL_FALSE;
576 }
577
578 dri2_dpy->dri3_major_version = dri3_query->major_version;
579 dri2_dpy->dri3_minor_version = dri3_query->minor_version;
580 free(dri3_query);
581
582 present_query =
583 xcb_present_query_version_reply(dri2_dpy->conn,
584 present_query_cookie, &error);
585 if (present_query == NULL || error != NULL) {
586 _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
587 free(present_query);
588 free(error);
589 return EGL_FALSE;
590 }
591
592 dri2_dpy->present_major_version = present_query->major_version;
593 dri2_dpy->present_minor_version = present_query->minor_version;
594 free(present_query);
595
596 xfixes_query =
597 xcb_xfixes_query_version_reply(dri2_dpy->conn,
598 xfixes_query_cookie, &error);
599 if (xfixes_query == NULL || error != NULL ||
600 xfixes_query->major_version < 2) {
601 _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
602 free(error);
603 free(xfixes_query);
604 return EGL_FALSE;
605 }
606 free(xfixes_query);
607
608 dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
609 if (dri2_dpy->fd < 0) {
610 int conn_error = xcb_connection_has_error(dri2_dpy->conn);
611 _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
612
613 if (conn_error)
614 _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
615
616 return EGL_FALSE;
617 }
618
619 dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
620
621 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
622 if (!dri2_dpy->driver_name) {
623 _eglLog(_EGL_WARNING, "DRI3: No driver found");
624 close(dri2_dpy->fd);
625 return EGL_FALSE;
626 }
627
628 #ifdef HAVE_WAYLAND_PLATFORM
629 /* Only try to get a render device name since dri3 doesn't provide a
630 * mechanism for authenticating client opened device node fds. If this
631 * fails then don't advertise the extension. */
632 dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);
633 #endif
634
635 return EGL_TRUE;
636 }
637