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