1 /*
2 * Copyright © 2015 Boyan Ding
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #include <fcntl.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <xcb/dri3.h>
30 #include <xcb/present.h>
31 #include <xcb/xcb.h>
32 #include <xcb/xfixes.h>
33
34 #include <xf86drm.h>
35 #include "util/macros.h"
36
37 #include "egl_dri2.h"
38 #include "platform_x11_dri3.h"
39
40 #include "loader.h"
41 #include "loader_dri3_helper.h"
42
43 static struct dri3_egl_surface *
loader_drawable_to_egl_surface(struct loader_dri3_drawable * draw)44 loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw)
45 {
46 size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);
47 return (struct dri3_egl_surface *)(((void *)draw) - offset);
48 }
49
50 static void
egl_dri3_set_drawable_size(struct loader_dri3_drawable * draw,int width,int height)51 egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw, int width,
52 int height)
53 {
54 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
55
56 dri3_surf->surf.base.Width = width;
57 dri3_surf->surf.base.Height = height;
58 }
59
60 static bool
egl_dri3_in_current_context(struct loader_dri3_drawable * draw)61 egl_dri3_in_current_context(struct loader_dri3_drawable *draw)
62 {
63 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
64 _EGLContext *ctx = _eglGetCurrentContext();
65
66 return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;
67 }
68
69 static __DRIcontext *
egl_dri3_get_dri_context(struct loader_dri3_drawable * draw)70 egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)
71 {
72 _EGLContext *ctx = _eglGetCurrentContext();
73 struct dri2_egl_context *dri2_ctx;
74 if (!ctx)
75 return NULL;
76 dri2_ctx = dri2_egl_context(ctx);
77 return dri2_ctx->dri_context;
78 }
79
80 static __DRIscreen *
egl_dri3_get_dri_screen(void)81 egl_dri3_get_dri_screen(void)
82 {
83 _EGLContext *ctx = _eglGetCurrentContext();
84 struct dri2_egl_context *dri2_ctx;
85 if (!ctx)
86 return NULL;
87 dri2_ctx = dri2_egl_context(ctx);
88 return dri2_egl_display(dri2_ctx->base.Resource.Display)
89 ->dri_screen_render_gpu;
90 }
91
92 static void
egl_dri3_flush_drawable(struct loader_dri3_drawable * draw,unsigned flags)93 egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
94 {
95 struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);
96 _EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;
97
98 dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);
99 }
100
101 static const struct loader_dri3_vtable egl_dri3_vtable = {
102 .set_drawable_size = egl_dri3_set_drawable_size,
103 .in_current_context = egl_dri3_in_current_context,
104 .get_dri_context = egl_dri3_get_dri_context,
105 .get_dri_screen = egl_dri3_get_dri_screen,
106 .flush_drawable = egl_dri3_flush_drawable,
107 };
108
109 static EGLBoolean
dri3_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)110 dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
111 {
112 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
113 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
114 xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;
115
116 loader_dri3_drawable_fini(&dri3_surf->loader_drawable);
117
118 if (surf->Type == EGL_PBUFFER_BIT)
119 xcb_free_pixmap(dri2_dpy->conn, drawable);
120
121 dri2_fini_surface(surf);
122 free(surf);
123
124 return EGL_TRUE;
125 }
126
127 static EGLBoolean
dri3_set_swap_interval(_EGLDisplay * disp,_EGLSurface * surf,EGLint interval)128 dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)
129 {
130 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
131
132 dri3_surf->surf.base.SwapInterval = interval;
133 loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);
134
135 return EGL_TRUE;
136 }
137
138 static enum loader_dri3_drawable_type
egl_to_loader_dri3_drawable_type(EGLint type)139 egl_to_loader_dri3_drawable_type(EGLint type)
140 {
141 switch (type) {
142 case EGL_WINDOW_BIT:
143 return LOADER_DRI3_DRAWABLE_WINDOW;
144 case EGL_PIXMAP_BIT:
145 return LOADER_DRI3_DRAWABLE_PIXMAP;
146 case EGL_PBUFFER_BIT:
147 return LOADER_DRI3_DRAWABLE_PBUFFER;
148 default:
149 return LOADER_DRI3_DRAWABLE_UNKNOWN;
150 }
151 }
152
153 static _EGLSurface *
dri3_create_surface(_EGLDisplay * disp,EGLint type,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)154 dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,
155 void *native_surface, const EGLint *attrib_list)
156 {
157 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
158 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
159 struct dri3_egl_surface *dri3_surf;
160 const __DRIconfig *dri_config;
161 xcb_drawable_t drawable;
162
163 dri3_surf = calloc(1, sizeof *dri3_surf);
164 if (!dri3_surf) {
165 _eglError(EGL_BAD_ALLOC, "dri3_create_surface");
166 return NULL;
167 }
168
169 if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list,
170 false, native_surface))
171 goto cleanup_surf;
172
173 if (type == EGL_PBUFFER_BIT) {
174 drawable = xcb_generate_id(dri2_dpy->conn);
175 xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, drawable,
176 dri2_dpy->screen->root, dri3_surf->surf.base.Width,
177 dri3_surf->surf.base.Height);
178 } else {
179 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));
180 drawable = (uintptr_t)native_surface;
181 }
182
183 dri_config =
184 dri2_get_dri_config(dri2_conf, type, dri3_surf->surf.base.GLColorspace);
185
186 if (!dri_config) {
187 _eglError(EGL_BAD_MATCH,
188 "Unsupported surfacetype/colorspace configuration");
189 goto cleanup_pixmap;
190 }
191
192 if (loader_dri3_drawable_init(
193 dri2_dpy->conn, drawable, egl_to_loader_dri3_drawable_type(type),
194 dri2_dpy->dri_screen_render_gpu, dri2_dpy->dri_screen_display_gpu,
195 dri2_dpy->multibuffers_available, true, dri_config,
196 &dri2_dpy->loader_dri3_ext, &egl_dri3_vtable,
197 &dri3_surf->loader_drawable)) {
198 _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
199 goto cleanup_pixmap;
200 }
201
202 if (dri3_surf->surf.base.ProtectedContent &&
203 dri2_dpy->fd_render_gpu != dri2_dpy->fd_display_gpu) {
204 _eglError(EGL_BAD_ALLOC, "dri3_surface_create");
205 goto cleanup_pixmap;
206 }
207
208 dri3_surf->loader_drawable.is_protected_content =
209 dri3_surf->surf.base.ProtectedContent;
210
211 return &dri3_surf->surf.base;
212
213 cleanup_pixmap:
214 if (type == EGL_PBUFFER_BIT)
215 xcb_free_pixmap(dri2_dpy->conn, drawable);
216 cleanup_surf:
217 free(dri3_surf);
218
219 return NULL;
220 }
221
222 static int
dri3_authenticate(_EGLDisplay * disp,uint32_t id)223 dri3_authenticate(_EGLDisplay *disp, uint32_t id)
224 {
225 #ifdef HAVE_WAYLAND_PLATFORM
226 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
227
228 if (dri2_dpy->device_name) {
229 _eglLog(_EGL_WARNING,
230 "Wayland client render node authentication is unnecessary");
231 return 0;
232 }
233
234 _eglLog(_EGL_WARNING,
235 "Wayland client primary node authentication isn't supported");
236 #endif
237
238 return -1;
239 }
240
241 /**
242 * Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
243 */
244 static _EGLSurface *
dri3_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)245 dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
246 void *native_window, const EGLint *attrib_list)
247 {
248 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
249 _EGLSurface *surf;
250
251 surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf, native_window,
252 attrib_list);
253 if (surf != NULL)
254 dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);
255
256 return surf;
257 }
258
259 static _EGLSurface *
dri3_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_pixmap,const EGLint * attrib_list)260 dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
261 void *native_pixmap, const EGLint *attrib_list)
262 {
263 return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf, native_pixmap,
264 attrib_list);
265 }
266
267 static _EGLSurface *
dri3_create_pbuffer_surface(_EGLDisplay * disp,_EGLConfig * conf,const EGLint * attrib_list)268 dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
269 const EGLint *attrib_list)
270 {
271 return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf, NULL, attrib_list);
272 }
273
274 static EGLBoolean
dri3_get_sync_values(_EGLDisplay * display,_EGLSurface * surface,EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)275 dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,
276 EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
277 {
278 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);
279
280 return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,
281 (int64_t *)ust, (int64_t *)msc,
282 (int64_t *)sbc)
283 ? EGL_TRUE
284 : EGL_FALSE;
285 }
286
287 static _EGLImage *
dri3_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)288 dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
289 EGLClientBuffer buffer, const EGLint *attr_list)
290 {
291 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
292 struct dri2_egl_image *dri2_img;
293 xcb_drawable_t drawable;
294 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
295 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
296 unsigned int format;
297
298 drawable = (xcb_drawable_t)(uintptr_t)buffer;
299 bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);
300 bp_reply =
301 xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn, bp_cookie, NULL);
302 if (!bp_reply) {
303 _eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");
304 return NULL;
305 }
306
307 format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
308 if (format == __DRI_IMAGE_FORMAT_NONE) {
309 _eglError(EGL_BAD_PARAMETER,
310 "dri3_create_image_khr: unsupported pixmap depth");
311 free(bp_reply);
312 return EGL_NO_IMAGE_KHR;
313 }
314
315 dri2_img = malloc(sizeof *dri2_img);
316 if (!dri2_img) {
317 _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
318 free(bp_reply);
319 return EGL_NO_IMAGE_KHR;
320 }
321
322 _eglInitImage(&dri2_img->base, disp);
323
324 dri2_img->dri_image = loader_dri3_create_image(
325 dri2_dpy->conn, bp_reply, format, dri2_dpy->dri_screen_render_gpu,
326 dri2_dpy->image, dri2_img);
327
328 free(bp_reply);
329
330 return &dri2_img->base;
331 }
332
333 #ifdef HAVE_DRI3_MODIFIERS
334 static _EGLImage *
dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)335 dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,
336 EGLClientBuffer buffer,
337 const EGLint *attr_list)
338 {
339 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
340 struct dri2_egl_image *dri2_img;
341 xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;
342 xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;
343 xcb_drawable_t drawable;
344 unsigned int format;
345
346 drawable = (xcb_drawable_t)(uintptr_t)buffer;
347 bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);
348 bp_reply =
349 xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn, bp_cookie, NULL);
350
351 if (!bp_reply) {
352 _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
353 return EGL_NO_IMAGE_KHR;
354 }
355
356 format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);
357 if (format == __DRI_IMAGE_FORMAT_NONE) {
358 _eglError(EGL_BAD_PARAMETER,
359 "dri3_create_image_khr: unsupported pixmap depth");
360 free(bp_reply);
361 return EGL_NO_IMAGE_KHR;
362 }
363
364 dri2_img = malloc(sizeof *dri2_img);
365 if (!dri2_img) {
366 _eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");
367 free(bp_reply);
368 return EGL_NO_IMAGE_KHR;
369 }
370
371 _eglInitImage(&dri2_img->base, disp);
372
373 dri2_img->dri_image = loader_dri3_create_image_from_buffers(
374 dri2_dpy->conn, bp_reply, format, dri2_dpy->dri_screen_render_gpu,
375 dri2_dpy->image, dri2_img);
376 free(bp_reply);
377
378 if (!dri2_img->dri_image) {
379 _eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");
380 free(dri2_img);
381 return EGL_NO_IMAGE_KHR;
382 }
383
384 return &dri2_img->base;
385 }
386 #endif
387
388 static _EGLImage *
dri3_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)389 dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
390 EGLClientBuffer buffer, const EGLint *attr_list)
391 {
392 #ifdef HAVE_DRI3_MODIFIERS
393 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
394 #endif
395
396 switch (target) {
397 case EGL_NATIVE_PIXMAP_KHR:
398 #ifdef HAVE_DRI3_MODIFIERS
399 if (dri2_dpy->multibuffers_available)
400 return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,
401 attr_list);
402 #endif
403 return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
404 default:
405 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
406 }
407 }
408
409 /**
410 * Called by the driver when it needs to update the real front buffer with the
411 * contents of its fake front buffer.
412 */
413 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)414 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
415 {
416 struct loader_dri3_drawable *draw = loaderPrivate;
417 (void)driDrawable;
418
419 /* There does not seem to be any kind of consensus on whether we should
420 * support front-buffer rendering or not:
421 * http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html
422 */
423 if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW)
424 _eglLog(_EGL_WARNING,
425 "FIXME: egl/x11 doesn't support front buffer rendering.");
426 }
427
428 const __DRIimageLoaderExtension dri3_image_loader_extension = {
429 .base = {__DRI_IMAGE_LOADER, 1},
430
431 .getBuffers = loader_dri3_get_buffers,
432 .flushFrontBuffer = dri3_flush_front_buffer,
433 };
434
435 static EGLBoolean
dri3_swap_buffers_with_damage(_EGLDisplay * disp,_EGLSurface * draw,const EGLint * rects,EGLint n_rects)436 dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,
437 const EGLint *rects, EGLint n_rects)
438 {
439 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);
440
441 return loader_dri3_swap_buffers_msc(
442 &dri3_surf->loader_drawable, 0, 0, 0, 0, rects, n_rects,
443 draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;
444 }
445
446 static EGLBoolean
dri3_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)447 dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
448 {
449 return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);
450 }
451
452 static EGLBoolean
dri3_copy_buffers(_EGLDisplay * disp,_EGLSurface * surf,void * native_pixmap_target)453 dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf,
454 void *native_pixmap_target)
455 {
456 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
457 xcb_pixmap_t target;
458
459 STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));
460 target = (uintptr_t)native_pixmap_target;
461
462 loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,
463 dri3_surf->loader_drawable.drawable);
464
465 return EGL_TRUE;
466 }
467
468 static int
dri3_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surf)469 dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)
470 {
471 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
472
473 return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);
474 }
475
476 static EGLBoolean
dri3_query_surface(_EGLDisplay * disp,_EGLSurface * surf,EGLint attribute,EGLint * value)477 dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf, EGLint attribute,
478 EGLint *value)
479 {
480 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
481
482 switch (attribute) {
483 case EGL_WIDTH:
484 case EGL_HEIGHT:
485 loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);
486 break;
487 default:
488 break;
489 }
490
491 return _eglQuerySurface(disp, surf, attribute, value);
492 }
493
494 static __DRIdrawable *
dri3_get_dri_drawable(_EGLSurface * surf)495 dri3_get_dri_drawable(_EGLSurface *surf)
496 {
497 struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);
498
499 return dri3_surf->loader_drawable.dri_drawable;
500 }
501
502 static void
dri3_close_screen_notify(_EGLDisplay * disp)503 dri3_close_screen_notify(_EGLDisplay *disp)
504 {
505 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
506
507 loader_dri3_close_screen(dri2_dpy->dri_screen_render_gpu);
508 }
509
510 struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
511 .authenticate = dri3_authenticate,
512 .create_window_surface = dri3_create_window_surface,
513 .create_pixmap_surface = dri3_create_pixmap_surface,
514 .create_pbuffer_surface = dri3_create_pbuffer_surface,
515 .destroy_surface = dri3_destroy_surface,
516 .create_image = dri3_create_image_khr,
517 .swap_interval = dri3_set_swap_interval,
518 .swap_buffers = dri3_swap_buffers,
519 .swap_buffers_with_damage = dri3_swap_buffers_with_damage,
520 .copy_buffers = dri3_copy_buffers,
521 .query_buffer_age = dri3_query_buffer_age,
522 .query_surface = dri3_query_surface,
523 .get_sync_values = dri3_get_sync_values,
524 .get_msc_rate = dri2_x11_get_msc_rate,
525 .get_dri_drawable = dri3_get_dri_drawable,
526 .close_screen_notify = dri3_close_screen_notify,
527 };
528
529 /* Only request versions of these protocols which we actually support. */
530 #define DRI3_SUPPORTED_MAJOR 1
531 #define PRESENT_SUPPORTED_MAJOR 1
532
533 #ifdef HAVE_DRI3_MODIFIERS
534 #define DRI3_SUPPORTED_MINOR 2
535 #define PRESENT_SUPPORTED_MINOR 2
536 #else
537 #define PRESENT_SUPPORTED_MINOR 0
538 #define DRI3_SUPPORTED_MINOR 0
539 #endif
540
541 enum dri2_egl_driver_fail
dri3_x11_connect(struct dri2_egl_display * dri2_dpy)542 dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
543 {
544 xcb_dri3_query_version_reply_t *dri3_query;
545 xcb_dri3_query_version_cookie_t dri3_query_cookie;
546 xcb_present_query_version_reply_t *present_query;
547 xcb_present_query_version_cookie_t present_query_cookie;
548 xcb_xfixes_query_version_reply_t *xfixes_query;
549 xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
550 xcb_generic_error_t *error;
551 const xcb_query_extension_reply_t *extension;
552
553 dri2_dpy->dri3_major_version = 0;
554 dri2_dpy->dri3_minor_version = 0;
555 dri2_dpy->present_major_version = 0;
556 dri2_dpy->present_minor_version = 0;
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 DRI2_EGL_DRIVER_FAILED;
565
566 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);
567 if (!(extension && extension->present))
568 return DRI2_EGL_DRIVER_FAILED;
569
570 extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);
571 if (!(extension && extension->present))
572 return DRI2_EGL_DRIVER_FAILED;
573
574 dri3_query_cookie = xcb_dri3_query_version(
575 dri2_dpy->conn, DRI3_SUPPORTED_MAJOR, DRI3_SUPPORTED_MINOR);
576
577 present_query_cookie = xcb_present_query_version(
578 dri2_dpy->conn, PRESENT_SUPPORTED_MAJOR, PRESENT_SUPPORTED_MINOR);
579
580 xfixes_query_cookie = xcb_xfixes_query_version(
581 dri2_dpy->conn, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
582
583 dri3_query =
584 xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);
585 if (dri3_query == NULL || error != NULL) {
586 _eglLog(_EGL_WARNING, "DRI3: failed to query the version");
587 free(dri3_query);
588 free(error);
589 return DRI2_EGL_DRIVER_FAILED;
590 }
591
592 dri2_dpy->dri3_major_version = dri3_query->major_version;
593 dri2_dpy->dri3_minor_version = dri3_query->minor_version;
594 free(dri3_query);
595
596 present_query = xcb_present_query_version_reply(
597 dri2_dpy->conn, present_query_cookie, &error);
598 if (present_query == NULL || error != NULL) {
599 _eglLog(_EGL_WARNING, "DRI3: failed to query Present version");
600 free(present_query);
601 free(error);
602 return DRI2_EGL_DRIVER_FAILED;
603 }
604
605 dri2_dpy->present_major_version = present_query->major_version;
606 dri2_dpy->present_minor_version = present_query->minor_version;
607 free(present_query);
608
609 xfixes_query = xcb_xfixes_query_version_reply(dri2_dpy->conn,
610 xfixes_query_cookie, &error);
611 if (xfixes_query == NULL || error != NULL ||
612 xfixes_query->major_version < 2) {
613 _eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");
614 free(error);
615 free(xfixes_query);
616 return DRI2_EGL_DRIVER_FAILED;
617 }
618 free(xfixes_query);
619
620 dri2_dpy->fd_render_gpu =
621 loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
622 if (dri2_dpy->fd_render_gpu < 0) {
623 int conn_error = xcb_connection_has_error(dri2_dpy->conn);
624 _eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");
625
626 if (conn_error)
627 _eglLog(_EGL_WARNING, "DRI3: Failed to initialize");
628
629 return DRI2_EGL_DRIVER_FAILED;
630 }
631
632 loader_get_user_preferred_fd(&dri2_dpy->fd_render_gpu,
633 &dri2_dpy->fd_display_gpu);
634
635 if (!dri2_dpy->driver_name)
636 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd_render_gpu);
637
638 if (!strcmp(dri2_dpy->driver_name, "zink")) {
639 close(dri2_dpy->fd_render_gpu);
640 return DRI2_EGL_DRIVER_PREFER_ZINK;
641 }
642
643 if (!dri2_dpy->driver_name) {
644 _eglLog(_EGL_WARNING, "DRI3: No driver found");
645 close(dri2_dpy->fd_render_gpu);
646 return DRI2_EGL_DRIVER_FAILED;
647 }
648
649 #ifdef HAVE_WAYLAND_PLATFORM
650 /* Only try to get a render device name since dri3 doesn't provide a
651 * mechanism for authenticating client opened device node fds. If this
652 * fails then don't advertise the extension. */
653 dri2_dpy->device_name =
654 drmGetRenderDeviceNameFromFd(dri2_dpy->fd_render_gpu);
655 #endif
656
657 return DRI2_EGL_DRIVER_LOADED;
658 }
659